Написал небольшой модуль для lua5.1
(в качестве эксперимента) на с++ (понятное дело функции экспортированы в C
). Модуль предоставляет объект массив чисел с такими операциями как: получить размер, установить значение, получить значение по индексу. Все просто, все понятно. Вот код:
// main.cpp
#include <iostream>
#include <iterator>
#include <lauxlib.h>
#include <lua.h>
#define ARRAY_META "levkovitch.array"
#pragma pack(1)
class LuaArray final {
public:
size_t size() const {
return *reinterpret_cast<size_t *>(ptr_);
}
float &operator[](int i) {
return (reinterpret_cast<float *>(ptr_) + sizeof(size_t))[i];
}
LuaArray(void *ptr)
: ptr_{ptr} {
}
void setSize(size_t size) {
*reinterpret_cast<size_t *>(ptr_) = size;
}
private:
void *ptr_;
};
extern "C" {
/**\brief create new array of floats with given size
*/
int lua_newarray(::lua_State *state) {
int size = ::luaL_checknumber(state, 1);
luaL_argcheck(state, size > 0, 1, "have to be number > 0");
LuaArray data =
::lua_newuserdata(state, sizeof(LuaArray) + size * sizeof(float));
data.setSize(size);
luaL_getmetatable(state, ARRAY_META);
::lua_setmetatable(state, -2);
return 1;
}
int lua_sizearray(::lua_State *state) {
LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
::lua_pushnumber(state, arr.size());
return 1;
}
int lua_setvalue(::lua_State *state) {
LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
int index = ::luaL_checknumber(state, 2);
float val = ::luaL_checknumber(state, 3);
luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
arr[index] = val;
return 0;
}
int lua_getvalue(::lua_State *state) {
LuaArray arr = ::lua_touserdata(state, 1);
int index = ::luaL_checknumber(state, 2);
luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
::lua_pushnumber(state, arr[index]);
return 1;
}
static const ::luaL_Reg arrayFuncs[] = {
{"new", lua_newarray},
{nullptr, nullptr},
};
static const ::luaL_Reg arrayMembers[] = {
{"getval", lua_getvalue},
{"setval", lua_setvalue},
{"size", lua_sizearray},
{nullptr, nullptr},
};
int luaopen_array(::lua_State *state) {
::luaL_newmetatable(state, ARRAY_META);
::lua_pushvalue(state, -1);
::lua_setfield(state, -2, "__index");
::luaL_openlib(state, nullptr, arrayMembers, 0);
::luaL_openlib(state, "array", arrayFuncs, 0);
return 1;
}
}
lua
local array = require("array")
local function main()
local arr = array.new(10)
if not arr then
print("invalid arr")
end
for i = 1, arr:size() do
arr:setval(i, i * 2)
end
for i = 1, arr:size() do
print(arr:getval(i))
end
end
main()
Все работает как и ожидалось, но возникли проблемы, когда я переделал код для доступа к вышеперечисленным методам через __len
, __index
, __newindex
поля метадаблицы:
// main.cpp
#include <iostream>
#include <iterator>
#include <lauxlib.h>
#include <lua.h>
#define ARRAY_META "levkovitch.array"
#pragma pack(1)
class LuaArray final {
public:
size_t size() const {
return *reinterpret_cast<size_t *>(ptr_);
}
float &operator[](int i) {
return (reinterpret_cast<float *>(ptr_) + sizeof(size_t))[i];
}
LuaArray(void *ptr)
: ptr_{ptr} {
}
void setSize(size_t size) {
*reinterpret_cast<size_t *>(ptr_) = size;
}
private:
void *ptr_;
};
extern "C" {
/**\brief create new array of floats with given size
*/
int lua_newarray(::lua_State *state) {
int size = ::luaL_checknumber(state, 1);
luaL_argcheck(state, size > 0, 1, "have to be number > 0");
LuaArray data =
::lua_newuserdata(state, sizeof(LuaArray) + size * sizeof(float));
data.setSize(size);
luaL_getmetatable(state, ARRAY_META);
::lua_setmetatable(state, -2);
return 1;
}
int lua_sizearray(::lua_State *state) {
LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
::lua_pushnumber(state, arr.size());
return 1;
}
int lua_setvalue(::lua_State *state) {
LuaArray arr = ::luaL_checkudata(state, 1, ARRAY_META);
int index = ::luaL_checknumber(state, 2);
float val = ::luaL_checknumber(state, 3);
luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
arr[index] = val;
return 0;
}
int lua_getvalue(::lua_State *state) {
LuaArray arr = ::lua_touserdata(state, 1);
int index = ::luaL_checknumber(state, 2);
luaL_argcheck(state, index > 0 && index <= (int)arr.size(), 2, "wrong index");
::lua_pushnumber(state, arr[index]);
return 1;
}
static const ::luaL_Reg arrayFuncs[] = {
{"new", lua_newarray},
{nullptr, nullptr},
};
static const ::luaL_Reg arrayMembers[] = {
{"__index", lua_getvalue},
{"__newindex", lua_setvalue},
{"__len", lua_sizearray},
{nullptr, nullptr},
};
int luaopen_array(::lua_State *state) {
::luaL_newmetatable(state, ARRAY_META);
::luaL_openlib(state, nullptr, arrayMembers, 0);
::luaL_openlib(state, "array", arrayFuncs, 0);
return 1;
}
}
lua
local array = require("array")
local function main()
local arr = array.new(10)
if not arr then
print("invalid arr")
end
for i = 1, #arr do
arr[i] = i * 2
end
for i = 1, #arr do
print(arr[i])
end
end
main()
Изменения минимальны и программа даже работает как ожидается до момента ее завершения, но падает при выходе. Почему? Предологаю, что дело в сборщике мусора, но что же все таки происходит?
PS когда ставлю collectgarbage()
до цикла с присваиванием, скрипт завершается без ошибки,а если сразу после цикла с присваиванием, то на этом месте вылетает segmentation fault
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Друзья, помогите с задачейКак сделать так, чтобы запись в файл производилась из всех файлов проекта(например
Есть у меня кнопка на ней ссылка которая передаёт значения!
Как получить данные из response в переменную res?