Created
July 31, 2017 07:36
-
-
Save cloudwu/98e52393cfa16f9299bc9492230d7b41 to your computer and use it in GitHub Desktop.
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 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