In the process of writing netcode, I realized how incredibly useful it would be if I could somehow know which values in a table have changed. Ideally these would be possible without me having to keep a whole copy of the table and constantly comparing. I thought I could do this with a metatable, however, the __newindex metamethod only gets called when assigning a value to a key which was previously empty - not whenever a value is updated.
Here was my attempt, however, it doesn't work right. It only finds when new values are added to the table, not when any value is updated.
function deltaTable(watch, delta)
setmetatable( watch, {
__newindex = function(t,k,v)
if v ~= rawget(t,k) then
rawset(delta,k,v)
end
rawset(t,k,v)
end
} )
end
Any suggestions?
Last edited by Taehl on Sun Feb 17, 2013 6:50 am, edited 1 time in total.
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit! Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
-- only downside: won't work with pairs()
function makeDeltaTable(t)
t = t or {}
t.__delta = {}
t.__index = function(t,k) return getmetatable(t)[k] end
t.__newindex = function(t,k,v)
if v ~= getmetatable(t)[k] then getmetatable(t).__delta[k] = v end
getmetatable(t)[k] = v
end
t.__unm = function(t) return getmetatable(t).__delta end -- -table returns full delta table
t.__sub = function(t,k) return getmetatable(t).__delta[k] end -- table-key returns delta value
return setmetatable( {}, t )
end
-- here are some tests:
t = makeDeltaTable( {x=10,y=10} )
t.x,t.y = 10,25 -- only t.y changed
print("delta t.x = "..tostring(t-"x")) -- nil, because x didn't change
for k,v in pairs(-t) do print("delta t."..k.." = "..v) end -- only shows delta t.y = 25
t.__delta = {} -- empty the delta table
print("t.__delta={}. Now delta t.y = "..tostring(t-"y")) -- nil
print("t.x, t.y = "..t.x..", "..t.y) -- 10, 25
Earliest Love2D supporter who can't Love anymore. Let me disable pixel shaders if I don't use them, dammit! Lenovo Thinkpad X60 Tablet, built like a tank. But not fancy enough for Love2D 0.10.0+.
-- only downside: won't work with pairs()
function makeDeltaTable(t)
t = t or {}
t.__delta = {}
t.__index = function(t,k) return getmetatable(t)[k] end
t.__newindex = function(t,k,v)
if v ~= getmetatable(t)[k] then getmetatable(t).__delta[k] = v end
getmetatable(t)[k] = v
end
t.__unm = function(t) return getmetatable(t).__delta end -- -table returns full delta table
t.__sub = function(t,k) return getmetatable(t).__delta[k] end -- table-key returns delta value
return setmetatable( {}, t )
end
-- here are some tests:
t = makeDeltaTable( {x=10,y=10} )
t.x,t.y = 10,25 -- only t.y changed
print("delta t.x = "..tostring(t-"x")) -- nil, because x didn't change
for k,v in pairs(-t) do print("delta t."..k.." = "..v) end -- only shows delta t.y = 25
t.__delta = {} -- empty the delta table
print("t.__delta={}. Now delta t.y = "..tostring(t-"y")) -- nil
print("t.x, t.y = "..t.x..", "..t.y) -- 10, 25
-- only downside: won't work with pairs()
function makeDeltaTable(t)
t = t or {}
t.__delta = {}
t.__index = t
t.__newindex = function(_,k,v)
if v ~= t[k] then t.__delta[k] = v end
t[k] = v
end
t.__unm = function(_) return t.__delta end -- -table returns full delta table
t.__sub = function(_,k) return t.__delta[k] end -- table-key returns delta value
return setmetatable( {}, t )
end
you could even go so far as making the delta table a local, in which case it'd automatically become private simply by being an upvalue of some of the metamethods (it'd also be slightly faster too)