blueloveTH 2 vuotta sitten
vanhempi
commit
a2caa487ab
3 muutettua tiedostoa jossa 190 lisäystä ja 15 poistoa
  1. 1 0
      amalgamate.py
  2. 36 0
      src/c.pyi
  3. 153 15
      src/cffi.h

+ 1 - 0
amalgamate.py

@@ -73,5 +73,6 @@ if os.path.exists("/mnt/e/PainterEngine/project/pocketpy.h"):
 	shutil.copy("amalgamated/pocketpy.h", "/mnt/e/PainterEngine/project/pocketpy.h")
 	shutil.copy("src/easing.pyi", "/mnt/e/PainterEngine/game/easing.pyi")
 	shutil.copy("src/linalg.pyi", "/mnt/e/PainterEngine/game/linalg.pyi")
+	shutil.copy("src/c.pyi", "/mnt/e/PainterEngine/game/c.pyi")
 
 

+ 36 - 0
src/c.pyi

@@ -0,0 +1,36 @@
+from typing import overload
+
+def malloc(size: int) -> 'void_p': ...
+def free(ptr: 'void_p') -> None: ...
+def sizeof(type: str) -> int: ...
+
+class void_p:
+    def __add__(self, i: int) -> 'void_p': ...
+    def __sub__(self, i: int) -> 'void_p': ...
+    def __eq__(self, other: 'void_p') -> bool: ...
+    def __ne__(self, other: 'void_p') -> bool: ...
+
+    def char(self) -> int: ...
+    def uchar(self) -> int: ...
+    def short(self) -> int: ...
+    def ushort(self) -> int: ...
+    def int(self) -> int: ...
+    def uint(self) -> int: ...
+    def long(self) -> int: ...
+    def ulong(self) -> int: ...
+    def longlong(self) -> int: ...
+    def ulonglong(self) -> int: ...
+    def float(self) -> float: ...
+    def double(self) -> float: ...
+    def bool(self) -> bool: ...
+    def void_p(self) -> 'void_p': ...
+
+    def get_base_offset(self) -> int: ...
+    @overload
+    def set_base_offset(self, offset: int) -> None: ...
+    @overload
+    def set_base_offset(self, offset: str) -> None: ...
+    
+class struct:
+    def address(self) -> 'void_p': ...
+    def copy(self) -> 'struct': ...

+ 153 - 15
src/cffi.h

@@ -29,13 +29,36 @@ namespace pkpy {
 
 #define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
 
+inline static int c99_sizeof(VM* vm, const Str& type){
+    static const std::map<Str, i64> c99_sizes = {
+        {"char", sizeof(char)},
+        {"uchar", sizeof(unsigned char)},
+        {"short", sizeof(short)},
+        {"ushort", sizeof(unsigned short)},
+        {"int", sizeof(int)},
+        {"uint", sizeof(unsigned int)},
+        {"long", sizeof(long)},
+        {"ulong", sizeof(unsigned long)},
+        {"longlong", sizeof(long long)},
+        {"ulonglong", sizeof(unsigned long long)},
+        {"float", sizeof(float)},
+        {"double", sizeof(double)},
+        {"bool", sizeof(bool)},
+        {"void_p", sizeof(void*)}
+    };
+    auto it = c99_sizes.find(type);
+    if(it != c99_sizes.end()) return it->second;
+    vm->ValueError("not a valid c99 type");
+    return 0;
+}
 
 struct VoidP{
     PY_CLASS(VoidP, c, void_p)
 
     void* ptr;
-    VoidP(void* ptr): ptr(ptr){}
-    VoidP(): ptr(nullptr){}
+    int base_offset;
+    VoidP(void* ptr): ptr(ptr), base_offset(1){}
+    VoidP(): ptr(nullptr), base_offset(1){}
 
     static void _register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_default_constructor<VoidP>(type);
@@ -43,32 +66,140 @@ struct VoidP{
         vm->bind_method<0>(type, "__repr__", [](VM* vm, ArgsView args){
             VoidP& self = _CAST(VoidP&, args[0]);
             std::stringstream ss;
-            ss << "<void* at " << self.ptr << ">";
+            ss << "<void* at " << self.ptr;
+            if(self.base_offset != 1) ss << ", base_offset=" << self.base_offset;
+            ss << ">";
             return VAR(ss.str());
         });
+
+        vm->bind_method<1>(type, "__eq__", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            VoidP& other = CAST(VoidP&, args[1]);
+            return VAR(self.ptr == other.ptr && self.base_offset == other.base_offset);
+        });
+
+        vm->bind_method<1>(type, "__ne__", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            VoidP& other = CAST(VoidP&, args[1]);
+            return VAR(self.ptr != other.ptr || self.base_offset != other.base_offset);
+        });
+
+        vm->bind_method<1>(type, "set_base_offset", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            if(is_non_tagged_type(args[1], vm->tp_str)){
+                const Str& type = _CAST(Str&, args[1]);
+                self.base_offset = c99_sizeof(vm, type);
+            }else{
+                self.base_offset = CAST(int, args[1]);
+            }
+            return vm->None;
+        });
+
+        vm->bind_method<0>(type, "get_base_offset", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            return VAR(self.base_offset);
+        });
+
+        vm->bind_method<1>(type, "__add__", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            i64 offset = CAST(i64, args[1]);
+            return VAR_T(VoidP, (char*)self.ptr + offset * self.base_offset);
+        });
+
+        vm->bind_method<1>(type, "__sub__", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            i64 offset = CAST(i64, args[1]);
+            return VAR_T(VoidP, (char*)self.ptr - offset * self.base_offset);
+        });
+
+#define BIND_SETGET(T, name) \
+        vm->bind_method<0>(type, name, [](VM* vm, ArgsView args){   \
+            VoidP& self = _CAST(VoidP&, args[0]);                   \
+            return VAR(*(T*)self.ptr);                              \
+        });                                                         \
+        vm->bind_method<1>(type, "set_" name, [](VM* vm, ArgsView args){   \
+            VoidP& self = _CAST(VoidP&, args[0]);                   \
+            *(T*)self.ptr = CAST(T, args[1]);                       \
+            return vm->None;                                        \
+        });
+
+        BIND_SETGET(char, "char")
+        BIND_SETGET(unsigned char, "uchar")
+        BIND_SETGET(short, "short")
+        BIND_SETGET(unsigned short, "ushort")
+        BIND_SETGET(int, "int")
+        BIND_SETGET(unsigned int, "uint")
+        BIND_SETGET(long, "long")
+        BIND_SETGET(unsigned long, "ulong")
+        BIND_SETGET(long long, "longlong")
+        BIND_SETGET(unsigned long long, "ulonglong")
+        BIND_SETGET(float, "float")
+        BIND_SETGET(double, "double")
+        BIND_SETGET(bool, "bool")
+
+        vm->bind_method<0>(type, "void_p", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            return VAR_T(VoidP, *(void**)self.ptr);
+        });
+        vm->bind_method<1>(type, "set_void_p", [](VM* vm, ArgsView args){
+            VoidP& self = _CAST(VoidP&, args[0]);
+            VoidP& other = CAST(VoidP&, args[0]);
+            self.ptr = other.ptr;
+            return vm->None;
+        });
     }
 };
 
-struct PlainOldData{
-    PY_CLASS(PlainOldData, c, pod)
+struct Struct{
+    PY_CLASS(Struct, c, struct)
+
+    static constexpr int INLINE_SIZE = 32;
 
+    char _inlined[INLINE_SIZE];
     char* p;
 
     template<typename T>
-    PlainOldData(const T& data){
+    Struct(const T& data){
         static_assert(std::is_pod_v<T>);
-        p = new char[sizeof(T)];
-        memcpy(p, &data, sizeof(T));
+        if(sizeof(T) <= INLINE_SIZE){
+            memcpy(_inlined, &data, sizeof(T));
+            p = _inlined;
+        }else{
+            p = (char*)malloc(sizeof(T));
+            memcpy(p, &data, sizeof(T));
+        }
     }
 
-    PlainOldData(): p(nullptr){}
-    ~PlainOldData(){ delete[] p; }
+    Struct() { p = _inlined; }
+    ~Struct(){ if(p!=_inlined) free(p); }
+
+    Struct(const Struct& other){
+        if(other.p == other._inlined){
+            memcpy(_inlined, other._inlined, INLINE_SIZE);
+            p = _inlined;
+        }else{
+            p = (char*)malloc(sizeof(other));
+            memcpy(p, other.p, sizeof(other));
+        }
+    }
 
     static void _register(VM* vm, PyObject* mod, PyObject* type){
-        vm->bind_default_constructor<PlainOldData>(type);
+        vm->bind_default_constructor<Struct>(type);
+
+        vm->bind_method<0>(type, "address", [](VM* vm, ArgsView args){
+            Struct& self = _CAST(Struct&, args[0]);
+            return VAR_T(VoidP, self.p);
+        });
+
+        vm->bind_method<0>(type, "copy", [](VM* vm, ArgsView args){
+            const Struct& self = _CAST(Struct&, args[0]);
+            return VAR_T(Struct, self);
+        });
     }
 };
 
+static_assert(sizeof(Py_<Struct>) <= 64);
+
 inline PyObject* py_var(VM* vm, void* p){
     return VAR_T(VoidP, p);
 }
@@ -87,13 +218,13 @@ T to_void_p(VM* vm, PyObject* var){
 template<typename T>
 T to_plain_old_data(VM* vm, PyObject* var){
     static_assert(std::is_pod_v<T>);
-    PlainOldData& pod = CAST(PlainOldData&, var);
+    Struct& pod = CAST(Struct&, var);
     return *reinterpret_cast<T*>(pod.p);
 }
 
 template<typename T>
 std::enable_if_t<std::is_pod_v<T> && !std::is_pointer_v<T>, PyObject*> py_var(VM* vm, const T& data){
-    return VAR_T(PlainOldData, data);
+    return VAR_T(Struct, data);
 }
 /*****************************************************************/
 struct NativeProxyFuncCBase {
@@ -148,7 +279,7 @@ inline void bind_any_c_fp(VM* vm, PyObject* obj, Str name, T fp){
 
 inline void add_module_c(VM* vm){
     PyObject* mod = vm->new_module("c");
-
+    
     vm->bind_func<1>(mod, "malloc", [](VM* vm, ArgsView args){
         i64 size = CAST(i64, args[0]);
         return VAR(malloc(size));
@@ -160,8 +291,15 @@ inline void add_module_c(VM* vm){
         return vm->None;
     });
 
+    vm->bind_func<1>(mod, "sizeof", [](VM* vm, ArgsView args){
+        const Str& type = CAST(Str&, args[0]);
+        i64 size = c99_sizeof(vm, type);
+        return VAR(size);
+    });
+
     VoidP::register_class(vm, mod);
-    PlainOldData::register_class(vm, mod);
+    Struct::register_class(vm, mod);
+    mod->attr().set("NULL", VAR_T(VoidP, nullptr));
 }
 
 }   // namespace pkpy