lua-users home
lua-l archive

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


> This is exactly the problem I'm trying to avoid.  The problem is when
> you call this millions of times you get millions of temporary objects.
>  It's slow (lots of memory allocation) and causes garbage collector
> thrashing.
> 
> Technically with that same approach it can look "proper":
> 
>    vertex_vector[20].x = 2.5
> 
> It's the same problem though with needing temporary objects.

Along these lines, have you tried caching temporary objects? You could use
something like this quick prototype:

-- vector.lua
local getmetatable, assert = getmetatable, assert
local newproxy, ipairs = newproxy, ipairs
local getfenv, setfenv = debug.getfenv, debug.setfenv

module(...)

local ud = {} -- cache userdata
local function register (d)
  local r = ud[d]
  if r == nil then
    r = newproxy(true)
    -- fill metatable
    local m = getmetatable(r)
    m.__index = function(u, k)
      local e = getfenv(u)
      local l = e._level
      local t = d[l]
      assert(t[k] ~= nil, "invalid key")
      local v = e[k]
      if v == nil and l < #d then
        v = new(d, l + 1)
        e[k] = v
      end
      return v
    end
    m.__newindex = function(u, k, v)
      local e = getfenv(u)
      local l = e._level
      assert(l == #d, "invalid level for assignment")
      e[k] = v
    end
    -- cache
    ud[d] = r
  end
  return r
end

function new (d, l) -- d is dimension table, l is level
  local l = l or 1
  local t = {_level = l}
  local u = newproxy(register(d))
  return setfenv(u, t)
end

-- utils
function range (f, t) -- from, to
  local r = {}
  for i = f, t do r[i] = true end
  return r
end

function labels (t)
  local l = {}
  for _, v in ipairs(t) do l[v] = true end
  return l
end

[ Test ]
$ lua -lvector
Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio
> u = vector.new{vector.range(1, 20), vector.labels{"x", "y", "z"}}
> print(u[20].x); u[20].x = 2.5
nil
> u[1].y = 1; print(u[20].x + u[1].y)
3.5

Of course, you have to provide your userdata to "new" at the first level and
use customized getters/setters in __index and __newindex. If GC is still an
issue, you could follow Diego's suggestion in the "high performance math"
thread earlier and use lightuserdata.

Cheers,
Luis.

-- 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos 

-- 
Luis Carvalho
Applied Math PhD Student
Brown University