diff --git a/amalgamate.py b/amalgamate.py index 6ff5f5f2..3efe4aaa 100644 --- a/amalgamate.py +++ b/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") diff --git a/src/c.pyi b/src/c.pyi new file mode 100644 index 00000000..828b1f68 --- /dev/null +++ b/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': ... \ No newline at end of file diff --git a/src/cffi.h b/src/cffi.h index d63634aa..3dcfe586 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -29,13 +29,36 @@ namespace pkpy { #define VAR_T(T, ...) vm->heap.gcnew(T::_type(vm), T(__VA_ARGS__)) +inline static int c99_sizeof(VM* vm, const Str& type){ + static const std::map 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(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 << ""; + 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 - PlainOldData(const T& data){ + Struct(const T& data){ static_assert(std::is_pod_v); - 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(type); + vm->bind_default_constructor(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_) <= 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 T to_plain_old_data(VM* vm, PyObject* var){ static_assert(std::is_pod_v); - PlainOldData& pod = CAST(PlainOldData&, var); + Struct& pod = CAST(Struct&, var); return *reinterpret_cast(pod.p); } template std::enable_if_t && !std::is_pointer_v, 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 \ No newline at end of file