replace Bytearray with FFI implementation
This commit is contained in:
parent
794aa5b9cd
commit
303e861fbb
@ -118,20 +118,22 @@ local bytearray_mt = {
|
||||
end
|
||||
}
|
||||
|
||||
local utf8tostring = utf8.tostring
|
||||
|
||||
function utf8.tostring(bytes)
|
||||
local type = _type(bytes)
|
||||
if type == "cdata" then
|
||||
return FFI.string(bytes.bytes, bytes.size)
|
||||
else
|
||||
return utf8tostring(bytes)
|
||||
end
|
||||
end
|
||||
|
||||
local bytearray_type = FFI.metatype("bytearray_t", bytearray_mt)
|
||||
|
||||
return function (n)
|
||||
local function FFIBytearray (n)
|
||||
local t = type(n)
|
||||
if t == "string" then
|
||||
local buffer = malloc(#n)
|
||||
FFI.copy(buffer, n, #n)
|
||||
return bytearray_type(buffer, #n, #n)
|
||||
elseif t == "table" then
|
||||
local capacity = math.max(#n, MIN_CAPACITY)
|
||||
local buffer = malloc(capacity)
|
||||
for i=1,#n do
|
||||
buffer[i - 1] = n[i]
|
||||
end
|
||||
return bytearray_type(buffer, #n, capacity)
|
||||
end
|
||||
n = n or 0
|
||||
if n < MIN_CAPACITY then
|
||||
return bytearray_type(malloc(MIN_CAPACITY), n, MIN_CAPACITY)
|
||||
@ -139,3 +141,23 @@ return function (n)
|
||||
return bytearray_type(malloc(n), n, n)
|
||||
end
|
||||
end
|
||||
|
||||
local function FFIBytearray_as_string(bytes)
|
||||
local t = type(bytes)
|
||||
if t == "cdata" then
|
||||
return FFI.string(bytes.bytes, bytes.size)
|
||||
elseif t == "table" then
|
||||
local buffer = FFI.new("unsigned char[?]", #bytes)
|
||||
for i=1, #bytes do
|
||||
buffer[i - 1] = bytes[i]
|
||||
end
|
||||
return FFI.string(buffer, #bytes)
|
||||
else
|
||||
error("Bytearray expected, got "..type(bytes))
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
FFIBytearray = FFIBytearray,
|
||||
FFIBytearray_as_string = FFIBytearray_as_string
|
||||
}
|
||||
|
||||
@ -263,7 +263,9 @@ entities.get_all = function(uids)
|
||||
return stdcomp.get_all(uids)
|
||||
end
|
||||
end
|
||||
FFIBytearray = require "core:internal/bytearray"
|
||||
local bytearray = require "core:internal/bytearray"
|
||||
Bytearray = bytearray.FFIBytearray
|
||||
Bytearray_as_string = bytearray.FFIBytearray_as_string
|
||||
ffi = nil
|
||||
|
||||
math.randomseed(time.uptime() * 1536227939)
|
||||
|
||||
@ -16,14 +16,14 @@ static int l_encode(lua::State* L) {
|
||||
return lua::pushstring(L, util::base64_encode(
|
||||
reinterpret_cast<const ubyte*>(buffer.data()), buffer.size()
|
||||
));
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L,
|
||||
util::base64_encode(
|
||||
bytes->data().data(),
|
||||
bytes->data().size()
|
||||
)
|
||||
} else {
|
||||
auto string = lua::bytearray_as_string(L, 1);
|
||||
auto out = util::base64_encode(
|
||||
reinterpret_cast<const ubyte*>(string.data()),
|
||||
string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushstring(L, std::move(out));
|
||||
}
|
||||
throw std::runtime_error("array or ByteArray expected");
|
||||
}
|
||||
@ -36,13 +36,10 @@ static int l_decode(lua::State* L) {
|
||||
lua::pushinteger(L, buffer[i] & 0xFF);
|
||||
lua::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, buffer.size());
|
||||
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
|
||||
bytearray->data().reserve(buffer.size());
|
||||
std::memcpy(bytearray->data().data(), buffer.data(), buffer.size());
|
||||
return lua::create_bytearray(L, buffer.data(), buffer.size());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg base64lib[] = {
|
||||
|
||||
@ -9,9 +9,7 @@ static int l_tobytes(lua::State* L) {
|
||||
if (lua::gettop(L) >= 2) {
|
||||
compress = lua::toboolean(L, 2);
|
||||
}
|
||||
return lua::newuserdata<lua::LuaBytearray>(
|
||||
L, json::to_binary(value, compress)
|
||||
);
|
||||
return lua::create_bytearray(L, json::to_binary(value, compress));
|
||||
}
|
||||
|
||||
static int l_frombytes(lua::State* L) {
|
||||
@ -24,17 +22,18 @@ static int l_frombytes(lua::State* L) {
|
||||
lua::pop(L);
|
||||
}
|
||||
return lua::pushvalue(L, json::from_binary(buffer.data(), len));
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, -1)) {
|
||||
const auto& buffer = bytes->data();
|
||||
return lua::pushvalue(
|
||||
L, json::from_binary(buffer.data(), buffer.size())
|
||||
);
|
||||
} else {
|
||||
throw std::runtime_error("table or Bytearray expected");
|
||||
auto string = lua::bytearray_as_string(L, 1);
|
||||
auto out = json::from_binary(
|
||||
reinterpret_cast<const ubyte*>(string.data()), string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushvalue(L, std::move(out));
|
||||
}
|
||||
}
|
||||
|
||||
const luaL_Reg bjsonlib[] = {
|
||||
{"tobytes", lua::wrap<l_tobytes>},
|
||||
{"frombytes", lua::wrap<l_frombytes>},
|
||||
{NULL, NULL}};
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@ -99,7 +99,7 @@ static int pack(lua::State* L, const char* format, bool usetable) {
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return lua::newuserdata<lua::LuaBytearray>(L, builder.build());
|
||||
return lua::create_bytearray(L, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,8 +130,8 @@ static int count_elements(const char* format) {
|
||||
static int l_unpack(lua::State* L) {
|
||||
const char* format = lua::require_string(L, 1);
|
||||
int count = count_elements(format);
|
||||
auto bytes = lua::require_bytearray(L, 2);
|
||||
ByteReader reader(bytes);
|
||||
auto bytes = lua::bytearray_as_string(L, 2);
|
||||
ByteReader reader(reinterpret_cast<const ubyte*>(bytes.data()), bytes.size());
|
||||
bool bigEndian = false;
|
||||
|
||||
for (size_t i = 0; format[i]; i++) {
|
||||
|
||||
@ -248,12 +248,14 @@ static int l_load_texture(lua::State* L) {
|
||||
}
|
||||
lua::pop(L);
|
||||
load_texture(buffer.data(), buffer.size(), lua::require_string(L, 2));
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
} else {
|
||||
auto string = lua::bytearray_as_string(L, 1);
|
||||
load_texture(
|
||||
bytes->data().data(),
|
||||
bytes->data().size(),
|
||||
reinterpret_cast<const ubyte*>(string.data()),
|
||||
string.size(),
|
||||
lua::require_string(L, 2)
|
||||
);
|
||||
lua::pop(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ static int l_read_bytes(lua::State* L) {
|
||||
auto bytes = io::read_bytes(path);
|
||||
|
||||
if (lua::gettop(L) < 2 || !lua::toboolean(L, 2)) {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, std::move(bytes));
|
||||
lua::create_bytearray(L, std::move(bytes));
|
||||
} else {
|
||||
lua::createtable(L, length, 0);
|
||||
int newTable = lua::gettop(L);
|
||||
@ -148,18 +148,12 @@ static int l_read_bytes(lua::State* L) {
|
||||
static int l_write_bytes(lua::State* L) {
|
||||
io::path path = get_writeable_path(L);
|
||||
|
||||
if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, 2)) {
|
||||
auto& bytes = bytearray->data();
|
||||
return lua::pushboolean(
|
||||
L, io::write_bytes(path, bytes.data(), bytes.size())
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<ubyte> bytes;
|
||||
lua::read_bytes_from_table(L, 2, bytes);
|
||||
return lua::pushboolean(
|
||||
L, io::write_bytes(path, bytes.data(), bytes.size())
|
||||
auto string = lua::bytearray_as_string(L, 2);
|
||||
bool res = io::write_bytes(
|
||||
path, reinterpret_cast<const ubyte*>(string.data()), string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushboolean(L, res);
|
||||
}
|
||||
|
||||
static int l_list_all_res(lua::State* L, const std::string& path) {
|
||||
|
||||
@ -109,13 +109,13 @@ static int l_send(lua::State* L, network::Network& network) {
|
||||
}
|
||||
lua::pop(L);
|
||||
connection->send(buffer.data(), size);
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 2)) {
|
||||
connection->send(
|
||||
reinterpret_cast<char*>(bytes->data().data()), bytes->data().size()
|
||||
);
|
||||
} else if (lua::isstring(L, 2)) {
|
||||
auto string = lua::tolstring(L, 2);
|
||||
connection->send(string.data(), string.length());
|
||||
} else {
|
||||
auto string = lua::bytearray_as_string(L, 2);
|
||||
connection->send(string.data(), string.length());
|
||||
lua::pop(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -140,13 +140,10 @@ static int l_recv(lua::State* L, network::Network& network) {
|
||||
lua::pushinteger(L, buffer[i] & 0xFF);
|
||||
lua::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, size);
|
||||
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
|
||||
bytearray->data().reserve(size);
|
||||
std::memcpy(bytearray->data().data(), buffer.data(), size);
|
||||
return lua::create_bytearray(L, buffer.data(), size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_available(lua::State* L, network::Network& network) {
|
||||
|
||||
@ -14,13 +14,10 @@ static int l_tobytes(lua::State* L) {
|
||||
lua::pushinteger(L, string[i] & 0xFF);
|
||||
lua::rawseti(L, i+1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
lua::newuserdata<lua::LuaBytearray>(L, string.length());
|
||||
auto bytearray = lua::touserdata<lua::LuaBytearray>(L, -1);
|
||||
bytearray->data().reserve(string.length());
|
||||
std::memcpy(bytearray->data().data(), string.data(), string.length());
|
||||
return lua::create_bytearray(L, string.data(), string.length());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_tostring(lua::State* L) {
|
||||
@ -35,16 +32,10 @@ static int l_tostring(lua::State* L) {
|
||||
}
|
||||
lua::pop(L);
|
||||
return lua::pushlstring(L, buffer.data(), size);
|
||||
} else if (auto bytes = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
return lua::pushstring(
|
||||
L,
|
||||
std::string(
|
||||
reinterpret_cast<char*>(bytes->data().data()),
|
||||
bytes->data().size()
|
||||
)
|
||||
);
|
||||
} else {
|
||||
lua::bytearray_as_string(L, 1);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_length(lua::State* L) {
|
||||
|
||||
@ -144,7 +144,7 @@ static int l_get_chunk_data(lua::State* L) {
|
||||
} else {
|
||||
chunkData = compressed_chunks::encode(*chunk);
|
||||
}
|
||||
return lua::newuserdata<lua::LuaBytearray>(L, std::move(chunkData));
|
||||
return lua::create_bytearray(L, std::move(chunkData));
|
||||
}
|
||||
|
||||
static void integrate_chunk_client(Chunk& chunk) {
|
||||
@ -175,14 +175,17 @@ static int l_set_chunk_data(lua::State* L) {
|
||||
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
int z = static_cast<int>(lua::tointeger(L, 2));
|
||||
auto buffer = lua::require_bytearray(L, 3);
|
||||
auto buffer = lua::bytearray_as_string(L, 3);
|
||||
|
||||
auto chunk = level->chunks->getChunk(x, z);
|
||||
if (chunk == nullptr) {
|
||||
return lua::pushboolean(L, false);
|
||||
}
|
||||
compressed_chunks::decode(
|
||||
*chunk, buffer.data(), buffer.size(), *content->getIndices()
|
||||
*chunk,
|
||||
reinterpret_cast<const ubyte*>(buffer.data()),
|
||||
buffer.size(),
|
||||
*content->getIndices()
|
||||
);
|
||||
if (controller->getChunksController()->lighting == nullptr) {
|
||||
return lua::pushboolean(L, true);
|
||||
@ -198,10 +201,16 @@ static int l_save_chunk_data(lua::State* L) {
|
||||
|
||||
int x = static_cast<int>(lua::tointeger(L, 1));
|
||||
int z = static_cast<int>(lua::tointeger(L, 2));
|
||||
auto buffer = lua::require_bytearray(L, 3);
|
||||
auto buffer = lua::bytearray_as_string(L, 3);
|
||||
|
||||
compressed_chunks::save(
|
||||
x, z, std::move(buffer), level->getWorld()->wfile->getRegions()
|
||||
x,
|
||||
z,
|
||||
std::vector(
|
||||
reinterpret_cast<const ubyte*>(buffer.data()),
|
||||
reinterpret_cast<const ubyte*>(buffer.data()) + buffer.size()
|
||||
),
|
||||
level->getWorld()->wfile->getRegions()
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -18,26 +18,6 @@ namespace lua {
|
||||
virtual const std::string& getTypeName() const = 0;
|
||||
};
|
||||
|
||||
class LuaBytearray : public Userdata {
|
||||
std::vector<ubyte> buffer;
|
||||
public:
|
||||
LuaBytearray(size_t capacity);
|
||||
LuaBytearray(std::vector<ubyte> buffer);
|
||||
LuaBytearray(const ubyte* data, size_t size);
|
||||
virtual ~LuaBytearray();
|
||||
|
||||
const std::string& getTypeName() const override {
|
||||
return TYPENAME;
|
||||
}
|
||||
inline std::vector<ubyte>& data() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int createMetatable(lua::State*);
|
||||
inline static std::string TYPENAME = "Bytearray";
|
||||
};
|
||||
static_assert(!std::is_abstract<LuaBytearray>());
|
||||
|
||||
class LuaHeightmap : public Userdata {
|
||||
std::shared_ptr<Heightmap> map;
|
||||
std::unique_ptr<fnl_state> noise;
|
||||
|
||||
@ -117,7 +117,6 @@ void lua::init_state(State* L, StateType stateType) {
|
||||
|
||||
initialize_libs_extends(L);
|
||||
|
||||
newusertype<LuaBytearray>(L);
|
||||
newusertype<LuaHeightmap>(L);
|
||||
newusertype<LuaVoxelFragment>(L);
|
||||
newusertype<LuaCanvas>(L);
|
||||
|
||||
@ -39,14 +39,16 @@ int l_crc32(lua::State* L) {
|
||||
string.length()
|
||||
)
|
||||
);
|
||||
} else if (auto bytearray = lua::touserdata<lua::LuaBytearray>(L, 1)) {
|
||||
auto& bytes = bytearray->data();
|
||||
return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size()));
|
||||
} else if (lua::istable(L, 1)) {
|
||||
std::vector<ubyte> bytes;
|
||||
lua::read_bytes_from_table(L, 1, bytes);
|
||||
return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size()));
|
||||
} else {
|
||||
throw std::runtime_error("invalid argument 1");
|
||||
auto string = lua::bytearray_as_string(L, 1);
|
||||
auto res = crc32(
|
||||
value, reinterpret_cast<const ubyte*>(string.data()), string.size()
|
||||
);
|
||||
lua::pop(L);
|
||||
return lua::pushinteger(L, res);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ int lua::pushvalue(State* L, const dv::value& value) {
|
||||
break;
|
||||
case value_type::bytes: {
|
||||
const auto& bytes = value.asBytes();
|
||||
newuserdata<LuaBytearray>(L, bytes.data(), bytes.size());
|
||||
create_bytearray(L, bytes.data(), bytes.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -128,18 +128,14 @@ dv::value lua::tovalue(State* L, int idx) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
if (auto bytes = touserdata<LuaBytearray>(L, idx)) {
|
||||
const auto& data = bytes->data();
|
||||
return std::make_shared<dv::objects::Bytes>(data.data(), data.size());
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
"lua type " + std::string(lua_typename(L, type)) +
|
||||
" is not supported"
|
||||
default: {
|
||||
auto data = bytearray_as_string(L, idx);
|
||||
auto bytes = std::make_shared<dv::objects::Bytes>(
|
||||
reinterpret_cast<const ubyte*>(data.data()), data.size()
|
||||
);
|
||||
pop(L);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -746,14 +746,22 @@ namespace lua {
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<ubyte> require_bytearray(lua::State* L, int idx) {
|
||||
if (auto* bytearray = lua::touserdata<LuaBytearray>(L, idx)) {
|
||||
return bytearray->data();
|
||||
} else if (lua::istable(L, idx)) {
|
||||
std::vector<ubyte> bytes;
|
||||
read_bytes_from_table(L, idx, bytes);
|
||||
return bytes;
|
||||
}
|
||||
throw std::runtime_error("bytearray expected");
|
||||
inline int create_bytearray(lua::State* L, const void* bytes, size_t size) {
|
||||
lua::requireglobal(L, "Bytearray");
|
||||
lua::pushlstring(
|
||||
L, std::string_view(reinterpret_cast<const char*>(bytes), size)
|
||||
);
|
||||
return lua::call(L, 1, 1);
|
||||
}
|
||||
|
||||
inline int create_bytearray(lua::State* L, const std::vector<ubyte>& bytes) {
|
||||
return create_bytearray(L, bytes.data(), bytes.size());
|
||||
}
|
||||
|
||||
inline std::string_view bytearray_as_string(lua::State* L, int idx) {
|
||||
lua::requireglobal(L, "Bytearray_as_string");
|
||||
lua::pushvalue(L, idx);
|
||||
lua::call(L, 1, 1);
|
||||
return lua::tolstring(L, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,206 +0,0 @@
|
||||
#include "../lua_custom_types.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "util/listutil.hpp"
|
||||
#include "../lua_util.hpp"
|
||||
|
||||
using namespace lua;
|
||||
|
||||
LuaBytearray::LuaBytearray(size_t capacity) : buffer(capacity) {
|
||||
buffer.resize(capacity);
|
||||
}
|
||||
|
||||
LuaBytearray::LuaBytearray(std::vector<ubyte> buffer) : buffer(std::move(buffer)) {
|
||||
}
|
||||
|
||||
LuaBytearray::LuaBytearray(const ubyte* data, size_t size) : buffer(data, data + size) {
|
||||
}
|
||||
|
||||
LuaBytearray::~LuaBytearray() {
|
||||
}
|
||||
|
||||
static int l_append(lua::State* L) {
|
||||
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
|
||||
if (lua::isnumber(L, 2)) {
|
||||
auto value = tointeger(L, 2);
|
||||
buffer->data().push_back(static_cast<ubyte>(value));
|
||||
} else if (lua::istable(L, 2)) {
|
||||
lua::read_bytes_from_table(L, 2, buffer->data());
|
||||
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 2)) {
|
||||
util::concat(buffer->data(), extension->data());
|
||||
} else {
|
||||
throw std::runtime_error("integer/table/Bytearray expected");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_insert(lua::State* L) {
|
||||
auto buffer = touserdata<LuaBytearray>(L, 1);
|
||||
if (buffer == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& data = buffer->data();
|
||||
auto index = tointeger(L, 2) - 1;
|
||||
if (static_cast<size_t>(index) > data.size()) {
|
||||
return 0;
|
||||
}
|
||||
if (lua::isnumber(L, 3)) {
|
||||
auto value = tointeger(L, 3);
|
||||
data.insert(data.begin() + index, static_cast<ubyte>(value));
|
||||
} else if (lua::istable(L, 3)) {
|
||||
std::vector<ubyte> temp;
|
||||
lua::read_bytes_from_table(L, 3, temp);
|
||||
data.insert(data.begin() + index, temp.begin(), temp.end());
|
||||
} else if (auto extension = lua::touserdata<LuaBytearray>(L, 3)) {
|
||||
const std::vector<ubyte>& src = extension->data();
|
||||
data.insert(data.begin() + index, src.begin(), src.end());
|
||||
} else {
|
||||
throw std::runtime_error("integer/table/Bytearray expected");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_remove(lua::State* L) {
|
||||
auto buffer = touserdata<LuaBytearray>(L, 1);
|
||||
if (buffer == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& data = buffer->data();
|
||||
auto index = tointeger(L, 2) - 1;
|
||||
if (static_cast<size_t>(index) > data.size()) {
|
||||
return 0;
|
||||
}
|
||||
data.erase(data.begin() + index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, lua_CFunction> methods {
|
||||
{"append", lua::wrap<l_append>},
|
||||
{"insert", lua::wrap<l_insert>},
|
||||
{"remove", lua::wrap<l_remove>},
|
||||
};
|
||||
|
||||
static int l_meta_meta_call(lua::State* L) {
|
||||
if (lua_istable(L, 2)) {
|
||||
size_t len = objlen(L, 2);
|
||||
std::vector<ubyte> buffer(len);
|
||||
buffer.resize(len);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
rawgeti(L, i + 1);
|
||||
buffer[i] = static_cast<ubyte>(tointeger(L, -1));
|
||||
pop(L);
|
||||
}
|
||||
return newuserdata<LuaBytearray>(L, std::move(buffer));
|
||||
}
|
||||
auto size = tointeger(L, 2);
|
||||
if (size < 0) {
|
||||
throw std::runtime_error("size can not be less than 0");
|
||||
}
|
||||
return newuserdata<LuaBytearray>(L, static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
static int l_meta_index(lua::State* L) {
|
||||
auto buffer = touserdata<LuaBytearray>(L, 1);
|
||||
if (buffer == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& data = buffer->data();
|
||||
if (isstring(L, 2)) {
|
||||
auto found = methods.find(tostring(L, 2));
|
||||
if (found != methods.end()) {
|
||||
return pushcfunction(L, found->second);
|
||||
}
|
||||
}
|
||||
auto index = tointeger(L, 2) - 1;
|
||||
if (static_cast<size_t>(index) > data.size()) {
|
||||
return 0;
|
||||
}
|
||||
return pushinteger(L, data.at(index));
|
||||
}
|
||||
|
||||
static int l_meta_newindex(lua::State* L) {
|
||||
auto buffer = touserdata<LuaBytearray>(L, 1);
|
||||
if (buffer == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& data = buffer->data();
|
||||
auto index = static_cast<size_t>(tointeger(L, 2) - 1);
|
||||
auto value = tointeger(L, 3);
|
||||
if (index >= data.size()) {
|
||||
if (index == data.size()) {
|
||||
data.push_back(static_cast<ubyte>(value));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
data[index] = static_cast<ubyte>(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_meta_len(lua::State* L) {
|
||||
if (auto buffer = touserdata<LuaBytearray>(L, 1)) {
|
||||
return pushinteger(L, buffer->data().size());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_meta_tostring(lua::State* L) {
|
||||
auto buffer = touserdata<LuaBytearray>(L, 1);
|
||||
if (buffer == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& data = buffer->data();
|
||||
if (data.size() > 512) {
|
||||
return pushstring(
|
||||
L, "bytearray[" + std::to_string(data.size()) + "]{...}"
|
||||
);
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << "bytearray[" << std::to_string(data.size()) << "]{";
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
if (i > 0) {
|
||||
ss << " ";
|
||||
}
|
||||
ss << static_cast<uint>(data[i]);
|
||||
}
|
||||
ss << "}";
|
||||
return pushstring(L, ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
static int l_meta_add(lua::State* L) {
|
||||
auto bufferA = touserdata<LuaBytearray>(L, 1);
|
||||
auto bufferB = touserdata<LuaBytearray>(L, 2);
|
||||
if (bufferA == nullptr || bufferB == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
auto& dataA = bufferA->data();
|
||||
auto& dataB = bufferB->data();
|
||||
|
||||
std::vector<ubyte> ab;
|
||||
ab.reserve(dataA.size() + dataB.size());
|
||||
ab.insert(ab.end(), dataA.begin(), dataA.end());
|
||||
ab.insert(ab.end(), dataB.begin(), dataB.end());
|
||||
return newuserdata<LuaBytearray>(L, std::move(ab));
|
||||
}
|
||||
|
||||
int LuaBytearray::createMetatable(lua::State* L) {
|
||||
createtable(L, 0, 6);
|
||||
pushcfunction(L, lua::wrap<l_meta_index>);
|
||||
setfield(L, "__index");
|
||||
pushcfunction(L, lua::wrap<l_meta_newindex>);
|
||||
setfield(L, "__newindex");
|
||||
pushcfunction(L, lua::wrap<l_meta_len>);
|
||||
setfield(L, "__len");
|
||||
pushcfunction(L, lua::wrap<l_meta_tostring>);
|
||||
setfield(L, "__tostring");
|
||||
pushcfunction(L, lua::wrap<l_meta_add>);
|
||||
setfield(L, "__add");
|
||||
|
||||
createtable(L, 0, 1);
|
||||
pushcfunction(L, lua::wrap<l_meta_meta_call>);
|
||||
setfield(L, "__call");
|
||||
setmetatable(L);
|
||||
return 1;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user