diff --git a/mods/util/overrides/table.lua b/mods/util/overrides/table.lua index f724b27..a0d32a5 100644 --- a/mods/util/overrides/table.lua +++ b/mods/util/overrides/table.lua @@ -1,17 +1,36 @@ -function table.equals(a, b) - for k, v in pairs(a) do - if not (b[k] and b[k] == v) then +local t2s = minetest.serialize +local error_message = [[ +Function %s does not pass self-test! +Expected results: %s +Test Results: %s +]] + +local function half_equals(t1, t2) + for k, v in pairs(t1) do + if not t2[k] then return false - end - end - for k, v in pairs(b) do - if not (a[k] and a[k] == v) then + elseif (type(v) == "table") then + if not half_equals(t2[k], v) then + return false + end + elseif not (t2[k] == v) then return false end end return true end +function table.equals(t1, t2) + if half_equals(t1, t2) and half_equals(t2, t1) then + return true + else + return false + end +end + +assert(table.equals({"a", "b", c = "d", e = {"f", "g", "h", {"h"}}}, {"a", "b", c = "d", e = {"f", "g", "h", {"h"}}})) +assert(not table.equals({a = 1}, {a = 2})) + function table.shuffle(t) for i = #t, 2, -1 do local j = math.random(i) @@ -28,13 +47,41 @@ end function table.is_in(t, value) for _, v in ipairs(t) do - if v == value then + if (type(value) == "table") and table.equals(t, value) then + return true + elseif v == value then return true end end return false end +-- Returns matching values between two tables +function table.match(t1, t2) + local results = {} + for k, v in pairs(t2) do + if (type(k) == "number") and table.is_in(t1, v) then + table.insert(results, v) + elseif not t1[k] then + break + elseif type(v) == "table" then + local tmp_tbl = table.match(t1[k], v) + if not table.equals(tmp_tbl, {}) then + results[k] = tmp_tbl + end + elseif t1[k] == t2[k] then + results[k] = v + end + end + return results +end + +local match_test_table = {"foo", "bar", bar = {1, 2, 3}, baz = "boo", foo = {"baz"}} +local match_expected_results = {"foo", bar = {1, 3}, baz = "boo"} +local match_test_results = table.match(match_test_table, {"foo", bar = {1, 3}, baz = "boo", "furb", foo = {"bar"}}) +local match_error_message = error_message:format("table.match", t2s(match_expected_results), t2s(match_test_results)) +assert(table.equals(match_expected_results, match_test_results), match_error_message) + -- Returns a sub-set of an indexed table which matches the given parameters function table.search(t, params) params = params or {} @@ -43,30 +90,10 @@ function table.search(t, params) local results = {} for _, entree in ipairs(t) do - local should_include = true - for key, value in pairs(params.includes) do - if type(value) == "table" then - for _, v in ipairs(value) do - if (not entree[key]) or (not table.is_in(entree[key], v)) then - should_include = false - end - end - elseif (entree[key] == nil) or (entree[key] ~= value) then - should_include = false - end - end - for key, value in pairs(params.excludes) do - if type(value) == "table" then - for _, v in ipairs(value) do - if entree[key] and (table.is_in(entree[key], v)) then - should_include = false - end - end - elseif entree[key] and entree[key] == value then - should_include = false - end - end - if should_include then + local includes_match = table.match(entree, params.includes) + local excludes_match = table.match(entree, params.excludes) + + if table.equals(includes_match, params.includes) and table.equals(excludes_match, {}) then table.insert(results, entree) end end @@ -74,7 +101,7 @@ function table.search(t, params) return results end -local test_table = { +local search_test_table = { {tags = {"a", "b", "c"}, num = 1, num2 = 3}, {tags = {"b", "c"}, num = 1, num2 = 4}, {tags = {"b"}, num = 2, num2 = 3}, @@ -82,15 +109,9 @@ local test_table = { {tags = {"a", "b"}, num = 1, num2 = 3}, } -local expected_results = {test_table[4]} - -local test_results = table.search(test_table, {includes = {tags = {"b"}, num = 1}, excludes = {tags = {"a"}, num2 = 4}}) - -local error_message = [[ -Function table.search does not pass self-test! -Expected results: %s -Test Results: %s -]] -error_message:format(minetest.serialize(expected_results), minetest.serialize(test_results)) - -assert(table.equals(test_results, expected_results), error_message) +local search_expected_results = {search_test_table[4]} +local search_test_results = table.search(search_test_table, + {includes = {tags = {"b"}, num = 1}, excludes = {tags = {"a"}, num2 = 4}}) +local search_error_message = + error_message:format("table.search", t2s(search_expected_results), t2s(search_test_results)) +assert(table.equals(search_test_results, search_expected_results), search_error_message)