Page 1 of 1
How to track table delta (solved?)
Posted: Sat Feb 16, 2013 8:20 am
by Taehl
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.
Code: Select all
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?
Re: How to track table delta?
Posted: Sat Feb 16, 2013 9:48 am
by Robin
Use a proxy table: the proxy remains empty and it only sets values in the other table.
You also need an __index for the proxy that takes values from that other table.
Re: How to track table delta?
Posted: Sun Feb 17, 2013 6:48 am
by Taehl
That's a good idea, Robin. Thanks. I ran with it in what's probably not the direction you had in mind, but what do you think of this?
Code: Select all
-- 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
Re: How to track table delta (solved?)
Posted: Sun Feb 17, 2013 9:51 am
by Robin
What I think of it depends on whether it works for you. If it does, great!
Re: How to track table delta (solved?)
Posted: Sun Feb 17, 2013 5:17 pm
by spectralcanine
You should probably make __delta private, but whatever fits your needs.
As to pairs, you can create your own iterator
Re: How to track table delta?
Posted: Sun Feb 17, 2013 7:21 pm
by Xgoff
Taehl wrote:That's a good idea, Robin. Thanks. I ran with it in what's probably not the direction you had in mind, but what do you think of this?
Code: Select all
-- 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
that could be prematurely optimized somewhat
Code: Select all
-- 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)