[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: pairs / ipairs protection
- From: "Adam D. Moss" <adam@...>
- Date: Mon, 23 Jun 2003 20:50:56 +0100
Hello!
I just rustled up the following to help my code suck less.
From within Lua code it replaces pairs() and ipairs() with
versions that catch writes to the table that is being iterated
over. Stick this in your code and you'll get a clear error
instead of undefined behaviour when writing to a table while
it's being iterated over by pairs() or ipairs().
BIG WARNING: If you break out of the loop early then you'll
have to explicitly remove the iterated table's protection
with Punprotect(table). :( :(
There are a couple of things that it doesn't catch.
One is the *removal* of table entries (ie. assignment of nil
to them) while iterating. Couldn't think of a way to do that.
The other is nested iteration over the same table (I haven't
tested it, but I think that you'll lose protection one or
two nested levels down, nothing too serious).
Hope it's useful... anyway.
local old_pairs, old_ipairs = pairs, ipairs;
local function block_write(tab,idx,val)
error("Attempted to write to a table that was being iterated over.");
end
local my_plain_metatable = {__newindex = block_write};
function Punprotect(table)
local mt = getmetatable(table);
if ((mt == my_plain_metatable) or not mt) then
setmetatable(table, nil);
else
mt.__newindex = mt.OLD__newindex;
mt.OLD__newindex = nil;
end
end
local function Pprotect(table)
local mt = getmetatable(table);
if (mt) then
mt.OLD__newindex = mt.__newindex;
mt.__newindex = block_write;
else
setmetatable(table, my_plain_metatable);
end
end
local function mynext(table, index)
local k,v = next(table, index);
if (k == nil) then
Punprotect(table);
end
return k,v;
end
local function myinext(table, index)
local k,v;
if (index ~= nil) then
k = index+1;
else
k = 1;
end
v = table[k]
if (v == nil) then
Punprotect(table);
return nil;
end
return k,v;
end
pairs = function(tab)
Pprotect(tab);
return mynext, tab;
end
ipairs = function(tab)
Pprotect(tab);
return myinext, tab;
end
--
Adam D. Moss . ,,^^ adam@gimp.org http://www.foxbox.org/ co:3
"Responsible parents don't raise kids in West Virginia."