From f0b66c43e6f1c80de3bd65b4b5780a399ff12488 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 18 Mar 2023 23:04:34 +0800 Subject: [PATCH] reimpl `random` --- python/random.py | 7 ++++++ python/this.py | 6 ++--- src/cffi.h | 49 ++++++++++++++++++++++++++++++++++++---- src/common.h | 4 +++- src/pocketpy.h | 58 ++++++++++++++++++++++++++++++------------------ 5 files changed, 94 insertions(+), 30 deletions(-) diff --git a/python/random.py b/python/random.py index 5fdcfcc6..9f925f6b 100644 --- a/python/random.py +++ b/python/random.py @@ -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) diff --git a/python/this.py b/python/this.py index 1ffe58b2..27341999 100644 --- a/python/this.py +++ b/python/this.py @@ -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) \ No newline at end of file +Namespaces are one honking great idea -- let's do more of those!""") \ No newline at end of file diff --git a/src/cffi.h b/src/cffi.h index 131e2ef0..de589893 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -9,11 +9,10 @@ namespace pkpy { template struct NativeProxyFunc { - using T = Ret(*)(Params...); - // using T = std::function; 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 +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(vm, args, std::make_index_sequence()); + } + + template + std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + T& self = py_cast(vm, args[0]); + (self.*func)(py_cast(vm, args[Is+1])...); + return vm->None; + } + + template + std::enable_if_t, PyVar> call(VM* vm, Args& args, std::index_sequence) { + T& self = py_cast(vm, args[0]); + __Ret ret = (self.*func)(py_cast(vm, args[Is+1])...); + return VAR(std::move(ret)); + } +}; + +template +auto native_proxy_callable(Ret(*func)(Params...)) { + return NativeProxyFunc(func); +} + +template +auto native_proxy_callable(Ret(T::*func)(Params...)) { + return NativeProxyMethod(func); +} + + template constexpr int type_index() { return 0; } template<> constexpr int type_index() { return 1; } @@ -480,6 +520,7 @@ py_var(VM* vm, T p){ template std::enable_if_t>, PyVar> py_var(VM* vm, T p){ + if constexpr(std::is_same_v) return p; const TypeInfo* type = _type_db.get(); return VAR_T(Value, type, &p); } diff --git a/src/common.h b/src/common.h index 0e5a632a..ba989292 100644 --- a/src/common.h +++ b/src/common.h @@ -26,8 +26,10 @@ #include #include #include +#include +#include -#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__) diff --git a/src/pocketpy.h b/src/pocketpy.h index 065aac46..2efe3941 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -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 dis(a, b); + return dis(gen); + } + + f64 random() { + std::uniform_real_distribution dis(0.0, 1.0); + return dis(gen); + } + + f64 uniform(f64 a, f64 b) { + std::uniform_real_distribution 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); }