lua-users home
lua-l archive

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


Peter Hill:
> Hmm, I notice that my new version (which I actually bothered to test this
> time!) happens to meet that condition, though I was not actively aiming
> for it :-).

Wim Couwenberg:
> I figured.

I presume you mean about not actively aiming for it (since that is where it
doesn't fully work).


> Try your example on this:
>    t = {a=11}
>    setmetatable(t,{__index={a=44}, __next=tnext})
>
> That'll keep Lua busy for a while.  :-)

You have great insight! Either you've thought about this a lot, or you're
just smarter than I. :-O

Because I wasn't aiming to handle duplicated key entries I didn't test that.
And I was too slack, letting the first test fall through to the nil-case
loop. Bad move.

So, how about this version? Am I there yet?


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

*cheers*
Peter Hill.