Skip to content

Instantly share code, notes, and snippets.

@daurnimator
Created April 5, 2011 01:28
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save daurnimator/902845 to your computer and use it in GitHub Desktop.
Save daurnimator/902845 to your computer and use it in GitHub Desktop.
A small library that will let you use luajit cdata how you would hope.
local ffi=require"ffi"
local topointer
local pointer_mt
local key_address , key_ctype , key_cdata , key_methods = {},{},{},{}
local function ispointer ( ob )
return getmetatable ( ob ) == pointer_mt
end
local function denormalise ( ob )
if ispointer ( ob ) then
return ob[key_cdata]
else
return ob
end
end
local function normalise ( ob )
if type ( ob ) == "cdata" then
return topointer ( ob )
else
return ob
end
end
pointer_mt = {
__tostring = function ( o )
return string.format ( "%s: 0x%08x" , tostring ( o[key_ctype] ):match("<.->") , o[key_address] )
end ;
__index = function ( o , k )
local m = o[key_methods]
if m then
local v = m [ k ]
if v then return v end
end
return normalise ( o[key_cdata] [ k ] )
end ;
__newindex = function ( o , k , v )
o[key_cdata] [ k ] = denormalise ( v )
end ;
__eq = function ( a , b ) return a[key_address] == b[key_address] end ;
__lt = function ( a , b ) return a[key_cdata] < b[key_cdata] end ;
__len = function ( a ) return #a[key_cdata] end ;
__add = function ( a , b ) return normalise ( denormalise ( a ) + denormalise ( b ) ) end ;
__sub = function ( a , b ) return normalise ( denormalise ( a ) - denormalise ( b ) ) end ;
__mul = function ( a , b ) return normalise ( denormalise ( a ) * denormalise ( b ) ) end ;
__div = function ( a , b ) return normalise ( denormalise ( a ) / denormalise ( b ) ) end ;
__mod = function ( a , b ) return normalise ( denormalise ( a ) % denormalise ( b ) ) end ;
__pow = function ( a , b ) return normalise ( denormalise ( a ) ^ denormalise ( b ) ) end ;
__unm = function ( a , b ) return normalise ( - denormalise ( b ) ) end ;
__tonumber = function ( o ) return tonumber ( o[key_cdata] ) end ;
}
local pointer_cache = setmetatable ( { } , { mode = "kv" } )
topointer = function ( cdata , methods )
assert ( type ( cdata ) == "cdata" , "Not cdata" )
local address = tonumber ( ffi.cast ( "intptr_t" , cdata ) )
local ctype = ffi.typeof ( cdata )
local v = pointer_cache [ address ]
if v then
assert ( tostring ( v[key_ctype] ) == tostring ( ctype ) , "Differing ctype" )
else
v = setmetatable ( {
[key_address] = address ;
[key_ctype] = ctype ;
[key_cdata] = cdata ;
[key_methods] = methods ;
} , pointer_mt )
pointer_cache [ address ] = v
end
return v
end
return {
topointer = topointer ;
new = function ( ct , methods )
return topointer ( ffi.new ( ct .. "*" , ffi.new ( ct ) ) , methods )
end ;
change_methods = function ( pointer , methods )
assert ( ispointer ( pointer ) )
pointer[key_methods] = methods
return pointer
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment