lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


This implementation here would be more computational expensive since every table
access is routed through a __index access, but it would map such a table on any
other table. It also will check, if the table key is still valid... 
Another problem will be iterating such tables. Pairs and ipairs won't work
anymore - same as next. I would suggest then to overload those functions for
that environment to take these shadowtables into account and traversing them -
as far as possible - correctly. This might be tricky however...

---
local cplist = {}
local function getshadow (tab)
	if cplist[tab] then 
		return cplist[tab] -- don't make multiple copies of the same table
	end 
	local mt = {cpfrom = tab}
	local shadow = {}
	local cp = {}
	setmetatable(shadow,mt)
	cplist[tab] = shadow
	
	function mt:__index (key)
		local val = cp[key]
		if val == nil then 
			val = tab[key]
			if type(val)=="table" then
				val = getshadow(val)
				cp[key] = val
			end
		elseif type(val)=="table" and 
				getmetatable(val).cpfrom~=cp[key] then
			cp[key] = nil
			return self[key]
		end
		return val
	end
	
	mt.__newindex = cp
	
	return shadow
end

st = { x = 5 , y = {a = 5, b = 4}}
cp = getshadow(st)
print("cp: ", cp.x, cp.y.a, cp.y.b)
print("st: ", st.x, st.y.a, st.y.b)
print "---"

cp.x = 2
cp.y.a = 4

print("cp: ", cp.x, cp.y.a, cp.y.b)
print("st: ", st.x, st.y.a, st.y.b)
print "---"

st.y = {a = 0, b = 0}
st.z = st.y
cp.z.a = 2
print("cp: ", cp.x, cp.y.a, cp.y.b,cp.z.a)
print("st: ", st.x, st.y.a, st.y.b,st.z.a)
print "---"

> gary ng <garyng2000 <at> yahoo.com> writes:
> 
> > I am wondering if this is possible. That is I want a
> > table which refers to another table if it doesn't have
> > the particular key and any write does not touch its
> > prototype. 
> 
> -- Here's one way to do it:
> 
> function getShadowTable (t)
>     local mt = {}
>     function mt:__index (k)
>         local v = t[k]
>         if type(v) ~= "table" then return v end
>         local shadow = getShadowTable(v)
>         self[k] = shadow
>         return shadow
>     end
>     return setmetatable({}, mt)
> end
> 
> -- It passes your requirements...
> 
> t1 = { a = 1, b = {} }
> t2 = getShadowTable(t1)
> 
> t1.b.a = 1
> assert(t2.b.a == 1)
> t2.b.a = 2
> assert(t1.b.a == 1)
> assert(t2.b.a == 2)
> 
> -- But there are problems if t1.b is replaced after t2.b is read.
> -- That may not arise in your application...
> 
> t1 = { a = 1, b = {} }
> t2 = getShadowTable(t1)
> 
> t1.b.a = 1
> assert(t2.b.a == 1)
> t1.b = { x = 2 }
> assert(t2.b.x == 2)     -- assertion fails
> 
> 
> 
>