From 303e861fbb4bfb9ec48954d4bf5bae3c6e7f25ed Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 7 Apr 2025 20:15:48 +0300 Subject: [PATCH] replace Bytearray with FFI implementation --- res/modules/internal/bytearray.lua | 46 +++- res/scripts/stdlib.lua | 4 +- src/logic/scripting/lua/libs/libbase64.cpp | 21 +- src/logic/scripting/lua/libs/libbjson.cpp | 19 +- src/logic/scripting/lua/libs/libbyteutil.cpp | 6 +- src/logic/scripting/lua/libs/libcore.cpp | 8 +- src/logic/scripting/lua/libs/libfile.cpp | 18 +- src/logic/scripting/lua/libs/libnetwork.cpp | 15 +- src/logic/scripting/lua/libs/libutf8.cpp | 19 +- src/logic/scripting/lua/libs/libworld.cpp | 19 +- src/logic/scripting/lua/lua_custom_types.hpp | 20 -- src/logic/scripting/lua/lua_engine.cpp | 1 - src/logic/scripting/lua/lua_overrides.cpp | 10 +- src/logic/scripting/lua/lua_util.cpp | 20 +- src/logic/scripting/lua/lua_util.hpp | 26 ++- .../lua/usertypes/lua_type_bytearray.cpp | 206 ------------------ 16 files changed, 125 insertions(+), 333 deletions(-) delete mode 100644 src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp diff --git a/res/modules/internal/bytearray.lua b/res/modules/internal/bytearray.lua index 95d3dc20..04eddc94 100644 --- a/res/modules/internal/bytearray.lua +++ b/res/modules/internal/bytearray.lua @@ -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 +} diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 29b74e64..558ba0f2 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -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) diff --git a/src/logic/scripting/lua/libs/libbase64.cpp b/src/logic/scripting/lua/libs/libbase64.cpp index 26f77eb6..5d50f1e8 100644 --- a/src/logic/scripting/lua/libs/libbase64.cpp +++ b/src/logic/scripting/lua/libs/libbase64.cpp @@ -16,14 +16,14 @@ static int l_encode(lua::State* L) { return lua::pushstring(L, util::base64_encode( reinterpret_cast(buffer.data()), buffer.size() )); - } else if (auto bytes = lua::touserdata(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(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(L, buffer.size()); - auto bytearray = lua::touserdata(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[] = { diff --git a/src/logic/scripting/lua/libs/libbjson.cpp b/src/logic/scripting/lua/libs/libbjson.cpp index fa3dcfd7..f9acd077 100644 --- a/src/logic/scripting/lua/libs/libbjson.cpp +++ b/src/logic/scripting/lua/libs/libbjson.cpp @@ -9,9 +9,7 @@ static int l_tobytes(lua::State* L) { if (lua::gettop(L) >= 2) { compress = lua::toboolean(L, 2); } - return lua::newuserdata( - 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(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(string.data()), string.size() + ); + lua::pop(L); + return lua::pushvalue(L, std::move(out)); } } const luaL_Reg bjsonlib[] = { {"tobytes", lua::wrap}, {"frombytes", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/libs/libbyteutil.cpp b/src/logic/scripting/lua/libs/libbyteutil.cpp index d2c13175..76bd9d37 100644 --- a/src/logic/scripting/lua/libs/libbyteutil.cpp +++ b/src/logic/scripting/lua/libs/libbyteutil.cpp @@ -99,7 +99,7 @@ static int pack(lua::State* L, const char* format, bool usetable) { } return 1; } else { - return lua::newuserdata(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(bytes.data()), bytes.size()); bool bigEndian = false; for (size_t i = 0; format[i]; i++) { diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 568802b3..7ebdbc38 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -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(L, 1)) { + } else { + auto string = lua::bytearray_as_string(L, 1); load_texture( - bytes->data().data(), - bytes->data().size(), + reinterpret_cast(string.data()), + string.size(), lua::require_string(L, 2) ); + lua::pop(L); } return 0; } diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 51c63e82..fa2b2954 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -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(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(L, 2)) { - auto& bytes = bytearray->data(); - return lua::pushboolean( - L, io::write_bytes(path, bytes.data(), bytes.size()) - ); - } - - std::vector 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(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) { diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index ffad16ee..9a77b843 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -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(L, 2)) { - connection->send( - reinterpret_cast(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(L, size); - auto bytearray = lua::touserdata(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) { diff --git a/src/logic/scripting/lua/libs/libutf8.cpp b/src/logic/scripting/lua/libs/libutf8.cpp index 4c1f484f..c0801b4d 100644 --- a/src/logic/scripting/lua/libs/libutf8.cpp +++ b/src/logic/scripting/lua/libs/libutf8.cpp @@ -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(L, string.length()); - auto bytearray = lua::touserdata(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(L, 1)) { - return lua::pushstring( - L, - std::string( - reinterpret_cast(bytes->data().data()), - bytes->data().size() - ) - ); + } else { + lua::bytearray_as_string(L, 1); + return 1; } - return 1; } static int l_length(lua::State* L) { diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index acf602c3..3e107f0e 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -144,7 +144,7 @@ static int l_get_chunk_data(lua::State* L) { } else { chunkData = compressed_chunks::encode(*chunk); } - return lua::newuserdata(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(lua::tointeger(L, 1)); int z = static_cast(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(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(lua::tointeger(L, 1)); int z = static_cast(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(buffer.data()), + reinterpret_cast(buffer.data()) + buffer.size() + ), + level->getWorld()->wfile->getRegions() ); return 0; } diff --git a/src/logic/scripting/lua/lua_custom_types.hpp b/src/logic/scripting/lua/lua_custom_types.hpp index e126ee72..1185ecbe 100644 --- a/src/logic/scripting/lua/lua_custom_types.hpp +++ b/src/logic/scripting/lua/lua_custom_types.hpp @@ -18,26 +18,6 @@ namespace lua { virtual const std::string& getTypeName() const = 0; }; - class LuaBytearray : public Userdata { - std::vector buffer; - public: - LuaBytearray(size_t capacity); - LuaBytearray(std::vector buffer); - LuaBytearray(const ubyte* data, size_t size); - virtual ~LuaBytearray(); - - const std::string& getTypeName() const override { - return TYPENAME; - } - inline std::vector& data() { - return buffer; - } - - static int createMetatable(lua::State*); - inline static std::string TYPENAME = "Bytearray"; - }; - static_assert(!std::is_abstract()); - class LuaHeightmap : public Userdata { std::shared_ptr map; std::unique_ptr noise; diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 1ae35d39..ca335c49 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -117,7 +117,6 @@ void lua::init_state(State* L, StateType stateType) { initialize_libs_extends(L); - newusertype(L); newusertype(L); newusertype(L); newusertype(L); diff --git a/src/logic/scripting/lua/lua_overrides.cpp b/src/logic/scripting/lua/lua_overrides.cpp index 2040392c..3af2fa65 100644 --- a/src/logic/scripting/lua/lua_overrides.cpp +++ b/src/logic/scripting/lua/lua_overrides.cpp @@ -39,14 +39,16 @@ int l_crc32(lua::State* L) { string.length() ) ); - } else if (auto bytearray = lua::touserdata(L, 1)) { - auto& bytes = bytearray->data(); - return lua::pushinteger(L, crc32(value, bytes.data(), bytes.size())); } else if (lua::istable(L, 1)) { std::vector 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(string.data()), string.size() + ); + lua::pop(L); + return lua::pushinteger(L, res); } } diff --git a/src/logic/scripting/lua/lua_util.cpp b/src/logic/scripting/lua/lua_util.cpp index 8cd77fb1..77937aef 100644 --- a/src/logic/scripting/lua/lua_util.cpp +++ b/src/logic/scripting/lua/lua_util.cpp @@ -61,7 +61,7 @@ int lua::pushvalue(State* L, const dv::value& value) { break; case value_type::bytes: { const auto& bytes = value.asBytes(); - newuserdata(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(L, idx)) { - const auto& data = bytes->data(); - return std::make_shared(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( + reinterpret_cast(data.data()), data.size() ); + pop(L); + return bytes; + } } } diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index ab45edb1..ba0cd3d7 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -746,14 +746,22 @@ namespace lua { } } - inline std::vector require_bytearray(lua::State* L, int idx) { - if (auto* bytearray = lua::touserdata(L, idx)) { - return bytearray->data(); - } else if (lua::istable(L, idx)) { - std::vector 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(bytes), size) + ); + return lua::call(L, 1, 1); + } + + inline int create_bytearray(lua::State* L, const std::vector& 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); } } diff --git a/src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp b/src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp deleted file mode 100644 index 41b4ee59..00000000 --- a/src/logic/scripting/lua/usertypes/lua_type_bytearray.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "../lua_custom_types.hpp" - -#include - -#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 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(L, 1)) { - if (lua::isnumber(L, 2)) { - auto value = tointeger(L, 2); - buffer->data().push_back(static_cast(value)); - } else if (lua::istable(L, 2)) { - lua::read_bytes_from_table(L, 2, buffer->data()); - } else if (auto extension = lua::touserdata(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(L, 1); - if (buffer == nullptr) { - return 0; - } - auto& data = buffer->data(); - auto index = tointeger(L, 2) - 1; - if (static_cast(index) > data.size()) { - return 0; - } - if (lua::isnumber(L, 3)) { - auto value = tointeger(L, 3); - data.insert(data.begin() + index, static_cast(value)); - } else if (lua::istable(L, 3)) { - std::vector temp; - lua::read_bytes_from_table(L, 3, temp); - data.insert(data.begin() + index, temp.begin(), temp.end()); - } else if (auto extension = lua::touserdata(L, 3)) { - const std::vector& 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(L, 1); - if (buffer == nullptr) { - return 0; - } - auto& data = buffer->data(); - auto index = tointeger(L, 2) - 1; - if (static_cast(index) > data.size()) { - return 0; - } - data.erase(data.begin() + index); - return 0; -} - -static std::unordered_map methods { - {"append", lua::wrap}, - {"insert", lua::wrap}, - {"remove", lua::wrap}, -}; - -static int l_meta_meta_call(lua::State* L) { - if (lua_istable(L, 2)) { - size_t len = objlen(L, 2); - std::vector buffer(len); - buffer.resize(len); - for (size_t i = 0; i < len; i++) { - rawgeti(L, i + 1); - buffer[i] = static_cast(tointeger(L, -1)); - pop(L); - } - return newuserdata(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(L, static_cast(size)); -} - -static int l_meta_index(lua::State* L) { - auto buffer = touserdata(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(index) > data.size()) { - return 0; - } - return pushinteger(L, data.at(index)); -} - -static int l_meta_newindex(lua::State* L) { - auto buffer = touserdata(L, 1); - if (buffer == nullptr) { - return 0; - } - auto& data = buffer->data(); - auto index = static_cast(tointeger(L, 2) - 1); - auto value = tointeger(L, 3); - if (index >= data.size()) { - if (index == data.size()) { - data.push_back(static_cast(value)); - } - return 0; - } - data[index] = static_cast(value); - return 0; -} - -static int l_meta_len(lua::State* L) { - if (auto buffer = touserdata(L, 1)) { - return pushinteger(L, buffer->data().size()); - } - return 0; -} - -static int l_meta_tostring(lua::State* L) { - auto buffer = touserdata(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(data[i]); - } - ss << "}"; - return pushstring(L, ss.str()); - } -} - -static int l_meta_add(lua::State* L) { - auto bufferA = touserdata(L, 1); - auto bufferB = touserdata(L, 2); - if (bufferA == nullptr || bufferB == nullptr) { - return 0; - } - auto& dataA = bufferA->data(); - auto& dataB = bufferB->data(); - - std::vector 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(L, std::move(ab)); -} - -int LuaBytearray::createMetatable(lua::State* L) { - createtable(L, 0, 6); - pushcfunction(L, lua::wrap); - setfield(L, "__index"); - pushcfunction(L, lua::wrap); - setfield(L, "__newindex"); - pushcfunction(L, lua::wrap); - setfield(L, "__len"); - pushcfunction(L, lua::wrap); - setfield(L, "__tostring"); - pushcfunction(L, lua::wrap); - setfield(L, "__add"); - - createtable(L, 0, 1); - pushcfunction(L, lua::wrap); - setfield(L, "__call"); - setmetatable(L); - return 1; -}