Last active
August 29, 2015 14:01
-
-
Save SoniEx2/fc5d3614614e4e3fe131 to your computer and use it in GitHub Desktop.
IRC friendly Lua table copy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- the following deep copy function never stack overflows from recursion | |
-- needs optimization tho | |
local function deep(inp,copies) | |
-- push | |
local stack = {{inp = inp, key = nil, value = nil, next = false, skipNext = false, out = nil}} | |
local currentResult | |
copies = (type(copies) == "table") and copies or {} | |
-- I run ZBS from stock Lua (5.1), it's not label-friendly | |
while true do | |
--::Return:: | |
if #stack == 0 then | |
return currentResult | |
end | |
local entry = stack[#stack] | |
if not entry.next then | |
entry.out = {} | |
copies[entry.inp] = entry.out | |
end | |
--::Next:: | |
local rep = false | |
local ret = false | |
while true do | |
repeat | |
local key,value = entry.key, entry.value | |
if not entry.skipNext then | |
key,value = next(entry.inp, entry.key) | |
if not key then | |
--goto Out | |
break | |
end | |
entry.key = key | |
end | |
entry.skipNext = false | |
entry.next = true | |
print(key, value) | |
if (type(key) ~= "table" or copies[key]) and (type(value) ~= "table" or copies[value]) then | |
rawset(entry.out,copies[key] or key,copies[value] or value) | |
entry.key,entry.value = key,value | |
--goto Next | |
rep = true | |
break | |
end | |
if not (type(key) ~= "table" or copies[key]) then | |
-- push | |
entry.skipNext = true | |
stack[#stack+1] = {inp = key, key = nil, value = nil, next = false, skipNext = false, out = nil} | |
elseif not (type(value) ~= "table" or copies[value]) then | |
-- push | |
entry.skipNext = true | |
stack[#stack+1] = {inp = value, key = nil, value = nil, next = false, skipNext = false, out = nil} | |
end | |
--goto Return | |
ret = true | |
break | |
until true | |
if not rep then break end | |
rep = false | |
end | |
if not ret then | |
--::Out:: | |
currentResult = entry.out | |
-- pop | |
stack[#stack] = nil | |
end | |
--goto Return | |
end | |
end | |
-- alt deepcopy function | |
-- not fully tested | |
-- good for tables with long chains, (as in a.b.c.d.e.etc...) bad for tables with lots of (unique table) entries (if you need this use the recursive one) | |
local function check(obj, todo, copies) | |
if copies[obj] ~= nil then | |
return copies[obj] | |
elseif type(obj) == "table" then | |
local t = {} | |
todo[obj] = t | |
copies[obj] = t | |
return t | |
end | |
return obj | |
end | |
local function deep(inp, copies) | |
local out, todo = {}, {} | |
copies = copies or {} | |
todo[inp], copies[inp] = out, out | |
-- we can't use pairs() here because we modify todo | |
while next(todo) do | |
local i, o = next(todo) | |
todo[i] = nil | |
for k, v in next, i do | |
rawset(o, check(k, todo, copies), check(v, todo, copies)) | |
end | |
end | |
return out | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local k,o,d = next,type | |
d = function(a,r,t) -- this function is d(eep), we use the function args to declare locals | |
if o{}~=o(a) then -- if type({}) (another way to get the string "table") ~= type(a) then | |
return a -- we can't copy it so we just return it | |
end | |
t={} | |
r=r or {} | |
r[a]=t -- set t as the recursive copy of a. you can override this with metatables | |
for x,y in k,a do -- for x,y in pairs(a) do (except we skip metatables by using next directly | |
t[r[x] or d(x,r)]=r[y] or d(y,r) -- t[copy of x] = copy of y !!! I should've used rawset here !!! | |
end | |
return t | |
end | |
-- set table.copy.shallow and table.copy.deep | |
-- we could also set the metatable so that calling it calls table.copy.deep | |
-- (or turn it into table.copy(table,deep) where deep is a boolean) | |
table.copy={shallow=function(a,b) -- this function is s(hallow) | |
b = {} -- the b argument is to save a "local " keyword (6 chars, where ",b" is 2) | |
for x,y in k,a do -- for x,y in pairs(a) do (except we skip metatables by using next directly) | |
b[x] = y | |
end | |
return b | |
end,deep=d} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local k,o,d=next,type d=function(a,r,t)if o{}~=o(a)then return a end t={}r=r or{}r[a]=t for x,y in k,a do t[r[x]or d(x,r)]=r[y]or d(y,r)end return t end table.copy={shallow=function(a,b)b={}for x,y in k,a do b[x]=y end return b end,deep=d} | |
-- one line, fits IRC just fine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- local copies | |
local next,type = next,type | |
local function deep(inp,copies) | |
if type(inp) ~= "table" then | |
return inp | |
end | |
local out = {} | |
copies = (type(copies) == "table") and copies or {} | |
copies[inp] = out -- use normal assignment so we use copies' metatable (if any) | |
for key,value in next,inp do -- skip metatables by using next directly | |
-- we want a copy of the key and the value | |
-- if one is not available on the copies table, we have to make one | |
-- we can't do normal assignment here because metatabled copies tables might set metatables | |
-- out[copies[key] or deep(key,copies)]=copies[value] or deep(value,copies) | |
rawset(out,copies[key] or deep(key,copies),copies[value] or deep(value,copies)) | |
end | |
return out | |
end | |
local function shallow(inp) | |
local out = {} | |
for key,value in next,inp do -- skip metatables by using next directly | |
out[key] = value | |
end | |
return out | |
end | |
-- set table.copy.shallow and table.copy.deep | |
-- we could also set the metatable so that calling it calls table.copy.deep | |
-- (or turn it into table.copy(table,deep) where deep is a boolean) | |
table.copy={shallow=shallow,deep=deep} | |
-- //////////// | |
-- // ADDONS // | |
-- //////////// | |
-- START metatable deep copy | |
local mtdeepcopy_mt = { | |
__newindex = function(t,k,v) | |
setmetatable(v,debug.getmetatable(k)) | |
rawset(t,k,v) | |
end | |
} | |
table.copy.deep_keep_metatable = function(inp) | |
return deep(inp,setmetatable({},mtdeepcopy_mt)) | |
end | |
-- END metatable deep copy | |
-- START metatable shallow copy | |
local mtshallowcopy_mt = { | |
__newindex = function(t,k,v) -- don't rawset() so that __index gets called | |
setmetatable(v,debug.getmetatable(k)) | |
end, | |
__index = function(t,k) | |
return k | |
end | |
} | |
table.copy.shallow_keep_metatable = function(inp) | |
return deep(inp,setmetatable({},mtshallowcopy_mt)) | |
end | |
-- END metatable shallow copy |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment