Re: Re[4]: ffi.istype() on arrays

  • From: Wolfgang Pupp <wolfgang.pupp@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Fri, 3 Jul 2015 00:22:50 +0200

First, are you *sure* you actually need this?
Couldn't you just let the cdata-codepath error out on its own when
passed an unsuitable argument?
Do you need the string to be mutable? Why not cast the Lua-string to
'const char *' and use the same code for all argument types?

Here's how you could do this.
It basically delegates the problem to the LuaJIT-FFI which does the
actual typechecking:

-- This implementation relies on your libc to behave (the C standard does
-- not *require* strncmp to accept invalid pointers even on zero length
-- comparisons AFAIK). But IMHO this seems unlikely to fail in practice.

local ffi = require'ffi'
local C, pcall, type = ffi.C, pcall, type
ffi.cdef[[
int strncmp(const char *a, const char *b, size_t sz);
]]

-- checks if something is a (non-null) char pointer or -array.
local function is_cstring(v)
if type(v) ~= 'cdata' or v == nil then return false end
return (pcall(C.strncmp, v, v, 0))
end

local lstring = 'test'
local chararr = ffi.new('char[5]', 'test')
local charptr = ffi.cast('char *', chararr)
local nullptr = ffi.cast('char *', nil)
local uintptr = ffi.cast('unsigned int *', 1)

print(is_cstring(lstring)) --> false
print(is_cstring(chararr)) --> true
print(is_cstring(charptr)) --> true
print(is_cstring(nullptr)) --> false
print(is_cstring(uintptr)) --> false

local select, random, write = select, math.random, io.write
io.output(jit.os == 'Windows' and 'NUL' or '/dev/null')
local t0 = os.clock()
for i=1,1e6 do
-- prevent the JIT from being clever
local v = select(random(1, 5), lstring, chararr, charptr, nullptr,
uintptr)

write(is_cstring(v) and 'A' or 'B')
end
print(os.clock() - t0)

-- About 1 million checks (plus overhead) per second on my puny laptop.
-- Unsuitable cdata-types are processed *much* slower than anything else.

--Wolfgang

Other related posts: