table: Rewrite *_copy to copy any kind of type

Allowing shallow_copy/deep_copy to accept any type makes it easier to
write generic code where you just want to copy some input without
knowing anything about it. Like an event system, save system, etc.

Add corresponding test.

Tests pass
This commit is contained in:
David Briscoe 2022-03-03 21:59:18 -08:00
parent c038546ae1
commit d48d4b0e81
2 changed files with 30 additions and 23 deletions

View File

@ -329,41 +329,40 @@ if not tablex.clear then
end end
-- Copy a table -- Copy a table
-- See shallow_overlay to shallow copy into another table to avoid garbage. -- See shallow_overlay to shallow copy into an existing table to avoid garbage.
function tablex.shallow_copy(t) function tablex.shallow_copy(t)
assert:type(t, "table", "tablex.copy - t", 1) if type(t) == "table" then
local into = {} local into = {}
for k, v in pairs(t) do for k, v in pairs(t) do
into[k] = v into[k] = v
end
return into
end end
return into return t
end end
local function deep_copy(t, copied) local function deep_copy(t, copied)
-- TODO: consider supporting deep_copy(3) so you can always use deep_copy without type checking local clone = t
local into = {} if type(t) == "table" then
for k, v in pairs(t) do if copied[t] then
local clone = v clone = copied[t]
if type(v) == "table" then elseif type(t.copy) == "function" then
if copied[v] then clone = t:copy()
clone = copied[v] assert:type(clone, "table", "copy() didn't return a copy")
elseif type(v.copy) == "function" then else
clone = v:copy() clone = {}
assert:type(clone, "table", "copy() didn't return a copy") for k, v in pairs(t) do
else clone[k] = deep_copy(v, copied)
clone = deep_copy(v, copied)
setmetatable(clone, getmetatable(v))
end end
copied[v] = clone setmetatable(clone, getmetatable(t))
copied[t] = clone
end end
into[k] = clone
end end
return into return clone
end end
-- Recursively copy values of a table. -- Recursively copy values of a table.
-- Retains the same keys as original table -- they're not cloned. -- Retains the same keys as original table -- they're not cloned.
function tablex.deep_copy(t) function tablex.deep_copy(t)
assert:type(t, "table", "tablex.deep_copy - t", 1)
return deep_copy(t, {}) return deep_copy(t, {})
end end

View File

@ -20,6 +20,10 @@ local function test_shallow_copy()
x = { a = { b = { 2 }, c = { 3 }, } } x = { a = { b = { 2 }, c = { 3 }, } }
r = tablex.shallow_copy(x) r = tablex.shallow_copy(x)
assert:equal(r.a, x.a) assert:equal(r.a, x.a)
x = 10
r = tablex.shallow_copy(x)
assert:equal(r, x)
end end
local function test_deep_copy() local function test_deep_copy()
@ -35,6 +39,10 @@ local function test_deep_copy()
assert(r.a ~= x.a) assert(r.a ~= x.a)
assert:equal(r.a.b[1], 2) assert:equal(r.a.b[1], 2)
assert:equal(r.a.c[1], 3) assert:equal(r.a.c[1], 3)
x = 10
r = tablex.deep_copy(x)
assert:equal(r, x)
end end