--[[ Various helpful functions ]] local util = {} function util.cartesian(...) -- cartesian(tbl1, tbl2, tbl3, ...) -- for each table, returns a permutation of key, value in tbl1, tbl2, ect. local args = {...} return coroutine.wrap(function() local cursors = {} -- cursors[1], cursors[3], ect. are the keys for k,v in ipairs(args) do local a,b = next(v,nil) cursors[(k*2) - 1] = a cursors[(k*2)] = b end coroutine.yield(unpack(cursors)) local any_left = true while any_left do while next(args[#args],cursors[#cursors - 1]) do local a,b = next(args[#args],cursors[#cursors - 1]) cursors[#cursors - 1] = a cursors[#cursors] = b coroutine.yield(unpack(cursors)) end any_left = false for i = #args, 1, -1 do if next(args[i],cursors[(i*2)-1]) then cursors[(i*2)-1], cursors[i*2] = next(args[i],cursors[(i*2)-1]) for j = i+1, #args do cursors[(j*2)-1], cursors[j*2] = next(args[j],nil) end coroutine.yield(unpack(cursors)) any_left = true break end end end end) end -- Override tostring to display more info about the table local old_tostring = tostring local numtabs = 0 local printed_tables = {} local function tostring_helper(el) assert(type(el) == "table", "Tried to call helper with something that was not a table, it was a " .. type(el)) local mt = getmetatable(el) if mt and mt.__tostring then return mt.__tostring(el) elseif printed_tables[el] == true then return old_tostring(el) else printed_tables[el] = true numtabs = numtabs + 1 local strbuilder = {"{"} for k,v in pairs(el) do local key,value if type(k) == "table" then key = tostring_helper(k) else key = old_tostring(k) end if type(v) == "table" then value = tostring_helper(v) else value = old_tostring(v) end strbuilder[#strbuilder + 1] = string.format("%s%s : %s", string.rep("\t",numtabs), key, value) end strbuilder[#strbuilder + 1] = string.rep("\t",numtabs - 1) .. "}" numtabs = numtabs - 1 return table.concat(strbuilder,"\n") end end function tostring(el) printed_tables = {} if type(el) == "table" then return tostring_helper(el) end return old_tostring(el) end return util