Skip to content

Instantly share code, notes, and snippets.

@cloudwu
Created July 31, 2017 07:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cloudwu/98e52393cfa16f9299bc9492230d7b41 to your computer and use it in GitHub Desktop.
Save cloudwu/98e52393cfa16f9299bc9492230d7b41 to your computer and use it in GitHub Desktop.
local shadowcopy = {}
local weak = { __mode = "k" }
local NIL = {}
local queue = setmetatable({}, weak) -- object -> queue
local map = setmetatable({}, weak) -- copy -> { object = obj, values = {} }
local direct_mt = {
__index = function(t,k)
return map[t].object[k]
end,
__newindex = function(t,k,v)
map[t].object[k] = v
-- print("DIRECT SET", map[t].object, k,v)
end,
}
local delay_mt = {
__index = function(t,k)
local v = map[t].values[k]
if v == nil then
return map[t].object[k]
end
if v == NIL then
v = nil
end
return v
end,
__newindex = function(t,k,v)
if v == nil then
v = NIL
end
map[t].values[k] = v
-- print("DELAY SET", map[t].object, k, v)
end,
}
function shadowcopy.grab(obj)
local q = queue[obj]
if q == nil then
q = {}
queue[obj] = q
else
setmetatable(q[#q], delay_mt)
end
local proxy = { object = obj, values = {} }
local ret = setmetatable({}, direct_mt)
map[ret] = proxy
table.insert(q, ret)
return ret
end
local function apply(proxy)
local obj = proxy.object
for k,v in pairs(proxy.values) do
if v == NIL then
v = nil
end
obj[k] = v
-- print("SET", obj, k, v)
end
end
function shadowcopy.release(copy)
local proxy = assert(map[copy])
map[copy] = nil
local q = queue[proxy.object]
if q == nil then
-- object collected
return
end
local n = #q
if q[n] == copy then
-- release last copy
q[n] = nil
if n == 1 then
queue[proxy.object] = nil
else
local p = q[n-1]
setmetatable(p, direct_mt)
apply(map[p])
end
else
for i=1,n-1 do
if q[i] == copy then
table.remove(q, i)
return
end
end
end
end
return shadowcopy
--[[
local sc = require "shadowcopy"
local obj = { x = 1, y = 2 }
local proxy1 = sc.grab(obj)
local proxy2 = sc.grab(obj)
proxy1.x = 2
proxy2.x = 3
sc.release(proxy2)
for k,v in pairs(obj) do
print(k,v)
end
]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment