Răsfoiți Sursa

reimpl `random`

blueloveTH 3 ani în urmă
părinte
comite
f0b66c43e6
5 a modificat fișierele cu 93 adăugiri și 29 ștergeri
  1. 7 0
      python/random.py
  2. 2 4
      python/this.py
  3. 45 4
      src/cffi.h
  4. 3 1
      src/common.h
  5. 36 20
      src/pocketpy.h

+ 7 - 0
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)

+ 2 - 4
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)
+Namespaces are one honking great idea -- let's do more of those!""")

+ 45 - 4
src/cffi.h

@@ -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);
 }

+ 3 - 1
src/common.h

@@ -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__)

+ 36 - 20
src/pocketpy.h

@@ -690,29 +690,45 @@ void add_module_re(VM* vm){
     });
 }
 
-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;
-    });
+struct Random{
+    PY_CLASS(Random, random, Random)
+    std::mt19937 gen;
 
-    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));
-    });
+    Random(){
+        gen.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
+    }
 
-    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);
-    });
+    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");
+    Random::register_class(vm, mod);
     CodeObject_ code = vm->compile(kPythonLibs["random"], "random.py", EXEC_MODE);
     vm->_exec(code, mod);
 }