Индексировать массив в структуре FFI

Итак, я пытаюсь создать модуль, который динамически определяет, используете ли вы Lua или LuaJIT, и создает таблицу или cstruct в зависимости. Поскольку вы не можете добавлять метатаблицы к каррейкам, у меня есть массив с именем _m в моей структуре.

Вот фрагмент соответствующего кода, ниже я приведу ссылку на репозиторий Git.

local mat4      = {}
local mat4_mt   = {}

-- Private constructor.
local function new(m)
    m = m or {
        0, 0, 0, 0,
        0, 0, 0, 0,
        0, 0, 0, 0,
        0, 0, 0, 0
    }
    m._m = m
    return setmetatable(m, mat4_mt)
end

-- Do the check to see if JIT is enabled. If so use the optimized FFI structs.
local status, ffi
if type(jit) == "table" and jit.status() then
    status, ffi = pcall(require, "ffi")
    if status then
        ffi.cdef "typedef struct { double _m[16]; } cpml_mat4;"
        new = ffi.typeof("cpml_mat4")
    end
end

function mat4.transpose(out, a)
    out[1]  = a[1]
    out[2]  = a[5]
    out[3]  = a[9]
    out[4]  = a[13]
    out[5]  = a[2]
    out[6]  = a[6]
    out[7]  = a[10]
    out[8]  = a[14]
    out[9]  = a[3]
    out[10] = a[7]
    out[11] = a[11]
    out[12] = a[15]
    out[13] = a[4]
    out[14] = a[8]
    out[15] = a[12]
    out[16] = a[16]

    return out
end

mat4_mt.__index = function(t, k)
    if type(t) == "cdata" then
        if type(k) == "number" then
            return t._m[k-1]
        end
    elseif type(k) == "number" then
        return t._m[k]
    end

    return rawget(mat4, k)
end

function mat4_mt.__call(_, a)
    return new(a)
end

if status then
    ffi.metatype(new, mat4_mt)
end

return setmetatable({}, mat4_mt)

Проблема здесь в том, что когда я пытаюсь вызвать транспонирование, я получаю следующую ошибку:

'struct 173' cannot be indexed with 'number'

Если вы проверите mat4_mt.__index, я попытаюсь определить, с каким типом я работаю, таблицей или cdata, и проиндексировать массив внутри структуры.

local mat4 = require "mat4"
local a = mat4()
local b = mat4():transpose(a) -- Error!

Идея состоит в том, что когда вы пытаетесь получить доступ, скажем, к a[4], он должен получить доступ к a._m[3] за кулисами, но этого явно не происходит, и я понятия не имею, почему.

Мысли?

https://github.com/excessive/cpml/blob/refactor/modules/mat4.lua


person Karai17    schedule 22.07.2016    source источник
comment
Приведенный выше код не работает, как указано. Мне пришлось заменить return new(a) на return new(a or {}). Ссылка больше не действительна. Я нашел это при поиске сообщения об ошибке, поэтому, возможно, ответ все еще ценен.   -  person Pedro Gimeno    schedule 30.01.2018


Ответы (1)


Это работает, но вам не хватает метатабличной записи __newindex, что приводит к сбою out[index] = value, поскольку он все еще пытается индексировать структуру, а не содержащееся в ней поле. Добавление этого решает проблему:

mat4_mt.__newindex = function(t, k, v)
    if type(t) == "cdata" then
        if type(k) == "number" then
            t._m[k-1] = v
        end
    elseif type(k) == "number" then
        t._m[k] = v
    else
        rawset(t, k, v)
    end
end
person Pedro Gimeno    schedule 31.01.2018