Next Metamethod For Index Table

lua-users home
wiki

Rewriting next() for when __index is a Table

To make a next() function that matches this indexing method (including the shadowing of higher level keys by lower level ones) you can use the following code...

function tnext(t,o)
  local i,v

  if o then
    -- 'o' is not nil (it is a real existing key).
    -- Locate the key's table.
    local r = t
    while not rawget(r,o) do
      local m = getmetatable(r)
      r = m and m.__index
      assert(type(r)=="table", "Key not in table")
    end

    -- Grab the next non-shadowed index
    local s
    i = o -- Start with the current index.
    repeat
      -- Get next real (non-nil) index.
      i,v = next(r,i)
      while (i==nil) do
        local m = getmetatable(r)
        r = m and m.__index
        if (r==nil) then return nil,nil end -- None left.
        assert(type(r)=="table", "__index must be table or nil")
        i,v = next(r)
      end
      -- Find the next index's level.
      s = t
      while not rawget(s,i) do
        local m = getmetatable(s)
        s = m and m.__index
      end
      -- If match then not shadowed, else repeat.
    until (r==s)
    -- Return it.
    return i,v

  else
    -- 'o' is nil, so want the first real key. Scan each table in
    -- turn until we find one (or give up if all are empty).
    while t do
      i,v = next(t)
      if i then break end
      local m = getmetatable(t)
      t = m and m.__index
      assert(t==nil or type(t)=="table", "__index must be table or nil")
    end
    return i,v
  end
end

Example usage

t = {a=111,  b=222, c=333}
u = {a=123, d=444}
setmetatable(t, {__index=u})
for i,v in tnext,t do print(i,v) end
will give a result of:
a  111
b  222
c  333
d  444

-- PeterHill

See Also


RecentChanges · preferences
edit · history
Last edited May 28, 2007 10:40 pm GMT (diff)