Comparison By Value

lua-users home
wiki

The function hashed below adds a metatable to the given table t, so that any write or read in the table will actually use a hash of the key instead of the key itself. This allows simulating the comparison of keys by values. To achieve that, make sure that two objects (table or userdata) that should have the same value have the same hash.

local function gethash(k)
  local hash = k
  local mt = getmetatable(k)
  local __hash = mt and mt.__hash
  if type(__hash)=='function' then
    hash = __hash(k)
  elseif type(__hash)~='nil' then
    hash = __hash
  end
  return hash
end

function hashed(t)
  return setmetatable(t, {
    __index = function(t, k)
      return t[gethash(k)]
    end,
    __newindex = function(t, k, v)
      rawset(t, gethash(k), v)
    end,
  })
end

-- example usage

local t1 = setmetatable({}, {__hash = 42})
local t2 = setmetatable({}, {__hash = 42})

local t = {}
t[t1] = "foo"
assert(t[t2]==nil)

t = hashed({})
t[t1] = "foo"
assert(t[t2]=="foo")
t[t2] = "bar"
assert(t[t1]=="bar")

Here's an alternate implementation --DavidManura

local mt = {
  __mode = 'kv',
  __index = function(t,k) return k end
}
local function newkeymap(t) return setmetatable(t or {}, mt) end

function hashed(t, keymap)
  return setmetatable(t, {
    __index    = function(t, k) return rawget(t, keymap[k]) end,
    __newindex = function(t, k, v) rawset(t, keymap[k], v) end,
  })
end

-- example usage

local t = {}
t.BAR = "foo"
assert(t.bar==nil)

local keymap = newkeymap { BAR = 'bar' }
t = hashed({}, keymap)
t.bar = "foo"
assert(t.BAR=="foo")
t.BAR = "bar"
assert(t.bar=="bar")

RecentChanges · preferences
edit · history
Last edited September 5, 2008 2:22 am GMT (diff)