Получить ссылку на userdata в таблице, используя luaL_ref? - PullRequest
0 голосов
/ 16 сентября 2018

Прежде всего, я прошу прощения за то, что не загрузил полный код.

Я пытаюсь преобразовать userdata в pointer, чтобы он мог быть передан другому lua чанку с помощью lua_rawgeti().

Если вы видите функцию outletRet(), она проверяет тип возвращаемого значения, а если это userdata, она передает указатель на другой кусок lua, вызывая outlet_pointer(), и, похоже, работает нормально.

И если userdata находится внутри table, вызывается функция outletTable(). И если один из его элементов является userdata, он также преобразует userdata в pointer и затем передает его другому фрагменту, вызывая outlet_pointer().

Однако, когда вызывается luaL_ref(L, LUA_REGISTRYINDEX), кажется, что он получает ссылку на целое table, а не только userdata внутри него.

Как получить ссылку на userdata, а не на весь table?

void ofLua::outletTable() //called from outletRet() below
{
    lua_pushvalue(L, -1);
    lua_pushnil(L);
    int ac = 0;
    t_atom *av = static_cast<t_atom *>(getbytes(sizeof(t_atom) * ac));
    while (lua_next(L, -2))
    {
        av = static_cast<t_atom *>(resizebytes(av, sizeof(t_atom) * ac,
                                               sizeof(t_atom) * (ac + 1)));
        if (lua_isboolean(L, -1))
        {
            av[ac].a_type = A_FLOAT;
            av[ac].a_w.w_float = static_cast<t_float>(lua_toboolean(L, -1));
        }
        else if (lua_isnumber(L, -1))
        {
            av[ac].a_type = A_FLOAT;
            av[ac].a_w.w_float = static_cast<t_float>(lua_tonumber(L, -1));
        }
        else if (lua_isstring(L, -1))
        {
            av[ac].a_type = A_SYMBOL;
            av[ac].a_w.w_symbol = gensym(lua_tostring(L, -1));
        }
        else if (lua_isuserdata(L, -1))
        {
            av[ac].a_type = A_POINTER;
        }
        ac++;
        lua_pop(L, 1);
    }
    lua_pop(L, 1);
    const ofeliaIO &io = dataPtr->io;
    if (io.hasMultiControlOutlets)
    {
        int last = (io.numOutlets >= ac ? ac : io.numOutlets) - 1;
        for (int i = last; i >= 0; --i)
        {
            if (av[i].a_type == A_FLOAT)
                outlet_float(io.outlets[i], av[i].a_w.w_float);
            else if (av[i].a_type == A_SYMBOL)
                outlet_symbol(io.outlets[i], av[i].a_w.w_symbol);
            else if (av[i].a_type == A_POINTER)
            {
                userDataRefVec.push_back(luaL_ref(L, LUA_REGISTRYINDEX));
                outlet_pointer(io.outlets[i], reinterpret_cast<t_gpointer *>(&userDataRefVec.back()));
                luaL_unref(L, LUA_REGISTRYINDEX, userDataRefVec.back());
                userDataRefVec.pop_back();
            }
        }
    }
    else
        outlet_list(dataPtr->ob.ob_outlet, &s_list, ac, av);
    freebytes(av, sizeof(t_atom) * ac);
}

void ofLua::outletRet()
{
    const ofeliaIO &io = dataPtr->io;
    if (!io.hasControlOutlet) return;
    if (lua_isnil(L, -1))
        outlet_bang(io.outlets[0]);
    else if (lua_isboolean(L, -1))
        outlet_float(io.outlets[0], static_cast<t_float>(lua_toboolean(L, -1)));
    else if (lua_isnumber(L, -1))
        outlet_float(io.outlets[0], static_cast<t_float>(lua_tonumber(L, -1)));
    else if (lua_isstring(L, -1))
        outlet_symbol(io.outlets[0], gensym(lua_tostring(L, -1)));
    else if (lua_isuserdata(L, -1))
    {
        userDataRefVec.push_back(luaL_ref(L, LUA_REGISTRYINDEX));
        outlet_pointer(io.outlets[0], reinterpret_cast<t_gpointer *>(&userDataRefVec.back()));
        luaL_unref(L, LUA_REGISTRYINDEX, userDataRefVec.back());
        userDataRefVec.pop_back();
    }
    else if (lua_istable(L, -1))
        outletTable();
}

1 Ответ

0 голосов
/ 16 сентября 2018

Я пытаюсь преобразовать пользовательские данные в указатель

Не. Это не то же самое, указатель не представляет данные пользователя. Вы не можете получить объект пользовательских данных Lua через указатель на его область данных.

Если вам нужно работать с пользовательскими данными на собственной стороне, сохраните пользовательские данные в реестре с помощью luaL_ref() и используйте возвращенное целое число в качестве ссылки. Позже вы можете извлечь этот объект из реестра и получить указатель на его область данных, когда вам нужно. Но не храните только указатель.

Что касается проблемы со ссылочной таблицей, объект, который будет сохранен в реестре с luaL_ref(), должен быть на вершине стека Lua. Но сейчас единственной вещью, которая остается на вершине стека Lua, является стол. Вы копируете значение этой таблицы для итерации с while(lua_next()), и все, что читается из таблицы в этом цикле, извлекается из стека в конце цикла.

Возможно, вам даже не нужно создавать структуру av и обрабатывать данные сразу же при сканировании исходной таблицы. Вам не нужно ссылаться на / отменять пользовательские данные тогда. Если вам действительно нужно это av, то вместо указателя на память пользовательских данных сохраните целочисленный индекс, возвращаемый luaL_ref(). И вы должны сделать это в первом цикле, а не во втором. Затем второй цикл должен выполнить lua_rawgeti(), чтобы получить объект пользовательских данных, и после обработки вы можете отменить его.

...