Merge pull request #627 from MihailRis/usertype-random-implementation

replace lua Random implementation with usertype
This commit is contained in:
MihailRis 2025-09-26 00:16:44 +03:00 committed by GitHub
commit 1f3b7f828d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 115 additions and 38 deletions

View File

@ -1,35 +0,0 @@
local Random = {}
local M = 2 ^ 31
local A = 1103515245
local C = 12345
function Random.randint(self)
self._seed = (A * self._seed + C) % M
return self._seed
end
function Random.random(self, a, b)
local num = self:randint() % M / M
if b then
return math.floor(num * (b - a + 1) + a)
elseif a then
return math.floor(num * a + 1)
else
return num
end
end
function Random.seed(self, number)
if type(number) ~= "number" then
error("number expected")
end
self._seed = number
end
return function(seed)
if seed and type(seed) ~= "number" then
error("number expected")
end
return setmetatable({_seed = seed or random.random(M)}, {__index = Random})
end

View File

@ -669,4 +669,33 @@ end
bit.compile = require "core:bitwise/compiler"
bit.execute = require "core:bitwise/executor"
random.Random = require "core:internal/random_generator"
function __vc_create_random_methods(random_methods)
local index = 1
local buffer = nil
local buffer_size = 64
function random_methods:bytes(n)
local bytes = Bytearray(n)
for i=1,n do
bytes[i] = self:random(255)
end
return bytes
end
function random_methods:random(a, b)
if not buffer or index > #buffer then
buffer = self:generate(buffer_size)
index = 1
end
local value = buffer[index]
if b then
value = math.floor(value * (b - a + 1) + a)
elseif a then
value = math.floor(value * a + 1)
end
index = index + 4
return value
end
return random_methods
end

View File

@ -22,7 +22,7 @@ static int l_random(lua::State* L) {
}
}
static int l_bytes(lua::State* L) {
static int l_generate(lua::State* L) {
size_t size = lua::tointeger(L, 1);
auto randomEngine = util::seeded_random_engine(random_device);
@ -40,7 +40,7 @@ static int l_uuid(lua::State* L) {
const luaL_Reg randomlib[] = {
{"random", lua::wrap<l_random>},
{"bytes", lua::wrap<l_bytes>},
{"bytes", lua::wrap<l_generate>},
{"uuid", lua::wrap<l_uuid>},
{NULL, NULL}
};

View File

@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <array>
#include <random>
#include "lua_commons.hpp"
@ -114,4 +115,20 @@ namespace lua {
std::shared_ptr<ImageData> mData;
};
static_assert(!std::is_abstract<LuaCanvas>());
class LuaRandom : public Userdata {
public:
std::mt19937 rng;
explicit LuaRandom(uint64_t seed) : rng(seed) {}
virtual ~LuaRandom() override = default;
const std::string& getTypeName() const override {
return TYPENAME;
}
static int createMetatable(lua::State*);
inline static std::string TYPENAME = "__vc_Random";
};
static_assert(!std::is_abstract<LuaRandom>());
}

View File

@ -169,5 +169,13 @@ State* lua::create_state(const EnginePaths& paths, StateType stateType) {
auto file = "res:scripts/stdmin.lua";
auto src = io::read_string(file);
lua::pop(L, lua::execute(L, 0, src, "core:scripts/stdmin.lua"));
newusertype<LuaRandom>(L);
if (getglobal(L, "random")) {
if (getglobal(L, "__vc_Random")) {
setfield(L, "Random");
}
pop(L);
}
return L;
}

View File

@ -275,6 +275,15 @@ namespace lua {
}
return nullptr;
}
template <class T>
inline T& require_userdata(lua::State* L, int idx) {
if (void* rawptr = lua_touserdata(L, idx)) {
return *static_cast<T*>(rawptr);
}
throw std::runtime_error("invalid 'self' value");
}
template <class T, typename... Args>
inline int newuserdata(lua::State* L, Args&&... args) {
const auto& found = usertypeNames.find(typeid(T));

View File

@ -0,0 +1,49 @@
#include "../lua_custom_types.hpp"
#include "../lua_util.hpp"
#include <chrono>
using namespace lua;
using namespace std::chrono;
static int l_generate(lua::State* L) {
std::uniform_int_distribution<> dist(0, std::numeric_limits<int>::max());
auto& rng = require_userdata<LuaRandom>(L, 1).rng;
size_t n = touinteger(L, 2);
createtable(L, n, 0);
for (size_t i = 0; i < n; i++) {
pushnumber(L, dist(rng) / (double)std::numeric_limits<int>::max());
rawseti(L, i + 1);
}
return 1;
}
static int l_meta_meta_call(lua::State* L) {
integer_t seed;
if (lua::isnoneornil(L, 1)) {
seed = system_clock::now().time_since_epoch().count();
} else {
seed = tointeger(L, 1);
}
return newuserdata<LuaRandom>(L, seed);
}
int LuaRandom::createMetatable(lua::State* L) {
createtable(L, 0, 3);
requireglobal(L, "__vc_create_random_methods");
createtable(L, 0, 0);
pushcfunction(L, wrap<l_generate>);
setfield(L, "generate");
call(L, 1, 1);
setfield(L, "__index");
createtable(L, 0, 1);
pushcfunction(L, wrap<l_meta_meta_call>);
setfield(L, "__call");
setmetatable(L);
return 1;
}