У меня хорошо работает система сценариев, использующая объекты пользовательских данных. Однако теперь я хочу иметь свойство в моих пользовательских данных, которое может принимать обычную таблицу.
Я думаю, что я должен сделать, это создать нормальную таблицу и настроить метатаблицу для использования моего текущего набора метаметодов, однако я изо всех сил пытаюсь понять, как это сделать — я уверен, что это простая настройка, я просто не вижу это прямо сейчас.
Мой существующий код выглядит так:
void
LuaContext::push(lua_State* state, boost::shared_ptr<LuaWrapped> wrapped) {
static struct luaL_Reg methods[] = {
{ "__index", LuaWrapped::static_get },
{ "__newindex", LuaWrapped::static_set },
{ "__len", LuaWrapped::static_len },
{ "__ipairs", LuaWrapped::static_ipairs },
{ "__pairs", LuaWrapped::static_pairs },
{ "__gc", LuaWrapped::static_gc },
{ "__eq", LuaWrapped::static_eq },
{ NULL, NULL }
};
LuaWrapped::Ptr **ptr = (LuaWrapped::Ptr **)lua_newuserdata(state, sizeof(LuaWrapped::Ptr *));
*ptr = new LuaWrapped::Ptr(wrapped);
if (luaL_newmetatable(state, "LuaWrapped")) {
lua_pushstring(state, "__index");
lua_pushvalue(state, -2);
lua_settable(state, -3);
luaL_openlib(state, NULL, methods, 0);
}
lua_setmetatable(state, -2);
}
__gc
метаметод там, чтобы удалить LuaWrapped::Ptr
класс (который является оберткой для boost::shared_ptr
). Я думаю, что я оставлю это вместе и сохраню указатель в поле lightuserdata на обычной таблице.
Экспериментальный пользовательский метатизатор против обычной проблемы таблицы (за обсуждение в комментариях):
void
LuaContext::push(lua_State* state, boost::shared_ptr<LuaWrapped> wrapped) {
static struct luaL_Reg methods[] = {
{ "__index", LuaWrapped::static_get },
{ "__newindex", LuaWrapped::static_set },
{ "__len", LuaWrapped::static_len },
{ "__ipairs", LuaWrapped::static_ipairs },
{ "__pairs", LuaWrapped::static_pairs },
{ "__gc", LuaWrapped::static_gc },
{ "__eq", LuaWrapped::static_eq },
{ NULL, NULL }
};
lua_newtable(state);
LuaContext::push(state, "pointer");
lua_pushlightuserdata(state, new LuaWrapped::Ptr(wrapped));
lua_settable(state, -3);
lua_newtable(state);
luaL_openlib(state, NULL, methods, 0);
lua_setmetatable(state, -2);
}
int
LuaWrapped::static_get(lua_State* state) {
int argc = lua_gettop(state);
for (int i = 1; i <= argc; i++) {
const char *type = lua_typename(state, i);
std::cout << type << std::endl;
}
....
Ожидаемый результат при получении:
таблица, строка
Фактический вывод на get (Lua 5.2, Ubuntu 14.04):
логическое, userdata
Хранение произвольных данных вместе с пользовательскими данными — это то, для чего нужны пользовательские среды / пользовательские значения.
Для этого необходимо использовать метод lua 5.2. lua_setuservalue
а также lua_getuservalue
функции для связи таблицы с пользовательскими данными. Затем эту таблицу можно использовать для хранения и извлечения произвольных значений, связанных с пользовательскими данными.
В lua 5.1 для этой цели использовалась более общая концепция среды lua_setfenv
а также lua_getfenv
но идея та же.