reimpl random

This commit is contained in:
blueloveTH 2023-03-18 23:04:34 +08:00
parent d6535aba93
commit f0b66c43e6
5 changed files with 94 additions and 30 deletions

View File

@ -1,3 +1,10 @@
_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
randint = _inst.randint
def shuffle(L):
for i in range(len(L)):
j = randint(i, len(L) - 1)

View File

@ -1,4 +1,4 @@
s = """The Zen of Python, by Tim Peters
print("""The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
@ -18,6 +18,4 @@ Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!"""
print(s)
Namespaces are one honking great idea -- let's do more of those!""")

View File

@ -9,11 +9,10 @@ namespace pkpy {
template<typename Ret, typename... Params>
struct NativeProxyFunc {
using T = Ret(*)(Params...);
// using T = std::function<Ret(Params...)>;
static constexpr int N = sizeof...(Params);
T func;
NativeProxyFunc(T func) : func(func) {}
using _Fp = Ret(*)(Params...);
_Fp func;
NativeProxyFunc(_Fp func) : func(func) {}
PyVar operator()(VM* vm, Args& args) {
if (args.size() != N) {
@ -35,6 +34,47 @@ struct NativeProxyFunc {
}
};
template<typename Ret, typename T, typename... Params>
struct NativeProxyMethod {
static constexpr int N = sizeof...(Params);
using _Fp = Ret(T::*)(Params...);
_Fp func;
NativeProxyMethod(_Fp func) : func(func) {}
PyVar operator()(VM* vm, Args& args) {
int actual_size = args.size() - 1;
if (actual_size != N) {
vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
}
return call<Ret>(vm, args, std::make_index_sequence<N>());
}
template<typename __Ret, size_t... Is>
std::enable_if_t<std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
T& self = py_cast<T&>(vm, args[0]);
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
return vm->None;
}
template<typename __Ret, size_t... Is>
std::enable_if_t<!std::is_void_v<__Ret>, PyVar> call(VM* vm, Args& args, std::index_sequence<Is...>) {
T& self = py_cast<T&>(vm, args[0]);
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
return VAR(std::move(ret));
}
};
template<typename Ret, typename... Params>
auto native_proxy_callable(Ret(*func)(Params...)) {
return NativeProxyFunc<Ret, Params...>(func);
}
template<typename Ret, typename T, typename... Params>
auto native_proxy_callable(Ret(T::*func)(Params...)) {
return NativeProxyMethod<Ret, T, Params...>(func);
}
template<typename T>
constexpr int type_index() { return 0; }
template<> constexpr int type_index<void>() { return 1; }
@ -480,6 +520,7 @@ py_var(VM* vm, T p){
template<typename T>
std::enable_if_t<!std::is_pointer_v<std::decay_t<T>>, PyVar>
py_var(VM* vm, T p){
if constexpr(std::is_same_v<T, PyVar>) return p;
const TypeInfo* type = _type_db.get<T>();
return VAR_T(Value, type, &p);
}

View File

@ -26,8 +26,10 @@
#include <map>
#include <set>
#include <algorithm>
#include <random>
#include <chrono>
#define PK_VERSION "0.9.3"
#define PK_VERSION "0.9.4"
#define PK_EXTRA_CHECK 0
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)

View File

@ -690,29 +690,45 @@ void add_module_re(VM* vm){
});
}
struct Random{
PY_CLASS(Random, random, Random)
std::mt19937 gen;
Random(){
gen.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
}
i64 randint(i64 a, i64 b) {
std::uniform_int_distribution<i64> dis(a, b);
return dis(gen);
}
f64 random() {
std::uniform_real_distribution<f64> dis(0.0, 1.0);
return dis(gen);
}
f64 uniform(f64 a, f64 b) {
std::uniform_real_distribution<f64> dis(a, b);
return dis(gen);
}
void seed(i64 seed) {
gen.seed(seed);
}
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<0>(type, "__new__", CPP_LAMBDA(VAR_T(Random)));
vm->bind_method<1>(type, "seed", native_proxy_callable(&Random::seed));
vm->bind_method<2>(type, "randint", native_proxy_callable(&Random::randint));
vm->bind_method<0>(type, "random", native_proxy_callable(&Random::random));
vm->bind_method<2>(type, "uniform", native_proxy_callable(&Random::uniform));
}
};
void add_module_random(VM* vm){
PyVar mod = vm->new_module("random");
std::srand(std::time(0));
vm->bind_func<1>(mod, "seed", [](VM* vm, Args& args) {
std::srand((unsigned int)CAST(i64, args[0]));
return vm->None;
});
vm->bind_func<0>(mod, "random", CPP_LAMBDA(VAR(std::rand() / (f64)RAND_MAX)));
vm->bind_func<2>(mod, "randint", [](VM* vm, Args& args) {
i64 a = CAST(i64, args[0]);
i64 b = CAST(i64, args[1]);
if(a > b) std::swap(a, b);
return VAR(a + std::rand() % (b - a + 1));
});
vm->bind_func<2>(mod, "uniform", [](VM* vm, Args& args) {
f64 a = CAST(f64, args[0]);
f64 b = CAST(f64, args[1]);
if(a > b) std::swap(a, b);
return VAR(a + (b - a) * std::rand() / (f64)RAND_MAX);
});
Random::register_class(vm, mod);
CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
vm->_exec(code, mod);
}