From 6062e34a29d94a578db5dfb68b93c3f35b82157b Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 29 Sep 2023 18:43:59 +0800 Subject: [PATCH] ... --- include/pocketpy/bindings.h | 22 ++-- include/pocketpy/cffi.h | 26 +---- include/pocketpy/common.h | 2 +- include/pocketpy/vm.h | 3 +- include/typings/c.pyi | 118 +++++++-------------- python/c.py | 27 ----- src/cffi.cpp | 203 ++++++++++++++---------------------- src/vm.cpp | 14 ++- tests/80_c.py | 49 +++++---- tests/99_cffi_2.py | 58 ----------- 10 files changed, 167 insertions(+), 355 deletions(-) delete mode 100644 python/c.py delete mode 100644 tests/99_cffi_2.py diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 713105e7..79d04c79 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -164,20 +164,18 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){ return VAR(self == other); \ }); \ -#define PY_POINTER_LIKE(wT) \ - vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){ \ +#define PY_POINTER_SETGETITEM(wT) \ + using vT = std::remove_pointer_t()._())>; \ + vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1){ \ wT& self = _CAST(wT&, _0); \ - if(!vm->isinstance(_1, wT::_type(vm))) return vm->NotImplemented; \ - wT& other = _CAST(wT&, _1); \ - return VAR(self._() == other._()); \ + i64 i = CAST(i64, _1); \ + return VAR(self._()[i]); \ }); \ - vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ \ - wT& self = _CAST(wT&, obj); \ - return reinterpret_cast(self._()); \ + vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* _0, PyObject* _1, PyObject* _2){ \ + wT& self = _CAST(wT&, _0); \ + i64 i = CAST(i64, _1); \ + self._()[i] = CAST(vT, _2); \ + return vm->None; \ }); \ - vm->bind_property(type, "_value: int", [](VM* vm, ArgsView args){ \ - wT& self = _CAST(wT&, args[0]); \ - return VAR(reinterpret_cast(self._())); \ - }); } // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/cffi.h b/include/pocketpy/cffi.h index 532c9a64..f5f2d1fe 100644 --- a/include/pocketpy/cffi.h +++ b/include/pocketpy/cffi.h @@ -29,9 +29,6 @@ namespace pkpy { #define VAR_T(T, ...) vm->heap.gcnew(T::_type(vm), __VA_ARGS__) -inline PyObject* py_var(VM* vm, void* p); -inline PyObject* py_var(VM* vm, char* p); - struct VoidP{ PY_CLASS(VoidP, c, void_p) @@ -58,6 +55,10 @@ struct VoidP{ static void _register(VM* vm, PyObject* mod, PyObject* type); }; +inline PyObject* py_var(VM* vm, void* p){ + return VAR_T(VoidP, p); +} + struct C99Struct{ PY_CLASS(C99Struct, c, struct) @@ -81,33 +82,14 @@ struct C99Struct{ } C99Struct(const C99Struct& other): C99Struct(other.p, other.size){} - ~C99Struct(){ if(p!=_inlined) free(p); } static void _register(VM* vm, PyObject* mod, PyObject* type); }; -struct ReflType{ - std::string_view name; - size_t size; -}; -inline static std::map _refl_types; - -inline void add_refl_type(std::string_view name, size_t size){ - ReflType type{name, size}; - _refl_types[name] = std::move(type); -} - static_assert(sizeof(Py_) <= 64); static_assert(sizeof(Py_) <= 64); -inline PyObject* py_var(VM* vm, void* p){ - return VAR_T(VoidP, p); -} - -inline PyObject* py_var(VM* vm, char* p){ - return VAR_T(VoidP, p); -} /***********************************************/ template T to_void_p(VM* vm, PyObject* var){ diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index c514b230..08fb1980 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -22,7 +22,7 @@ #include #include -#define PK_VERSION "1.2.3" +#define PK_VERSION "1.2.4" #include "config.h" #include "export.h" diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 3d597cff..8c3e82a1 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -167,7 +167,8 @@ public: PyObject* py_iter(PyObject* obj); PyObject* find_name_in_mro(PyObject* cls, StrName name); - bool isinstance(PyObject* obj, Type cls_t); + bool isinstance(PyObject* obj, Type base); + bool issubclass(Type cls, Type base); PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr); PyObject* exec(Str source); PyObject* eval(Str source); diff --git a/include/typings/c.pyi b/include/typings/c.pyi index b78a1ab8..1ab69684 100644 --- a/include/typings/c.pyi +++ b/include/typings/c.pyi @@ -1,64 +1,53 @@ -from typing import overload +from typing import overload, Generic, TypeVar def malloc(size: int) -> 'void_p': ... def free(ptr: 'void_p') -> None: ... -def sizeof(type: str) -> int: ... def memset(ptr: 'void_p', value: int, size: int) -> None: ... def memcpy(dst: 'void_p', src: 'void_p', size: int) -> None: ... +T = TypeVar('T') +Tp = TypeVar('Tp', bound='void_p') + +def p_cast(ptr: 'void_p', cls: type[T]) -> T: + """Cast a pointer to a specific type.""" +def p_value(ptr: 'void_p') -> int: + """Get the value of a pointer.""" +def pp_deref(ptr: Tp) -> Tp: + """Dereference a double pointer.""" + class void_p: def __init__(self, addr: int): ... - 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 __lt__(self, other: 'void_p') -> bool: ... + def __le__(self, other: 'void_p') -> bool: ... + def __gt__(self, other: 'void_p') -> bool: ... + def __ge__(self, other: 'void_p') -> bool: ... def __hash__(self) -> int: ... + def __repr__(self) -> str: ... - def hex(self) -> str: ... +class Pointer(Generic[T], void_p): + def read(self) -> T: ... + def write(self, value: T) -> None: ... + def __getitem__(self, index: int) -> T: ... + def __setitem__(self, index: int, value: T) -> None: ... - @property - def _value(self) -> int: ... - - def read_char(self) -> int: ... - def read_uchar(self) -> int: ... - def read_short(self) -> int: ... - def read_ushort(self) -> int: ... - def read_int(self) -> int: ... - def read_uint(self) -> int: ... - def read_long(self) -> int: ... - def read_ulong(self) -> int: ... - def read_longlong(self) -> int: ... - def read_ulonglong(self) -> int: ... - def read_float(self) -> float: ... - def read_double(self) -> float: ... - def read_bool(self) -> bool: ... - def read_void_p(self) -> 'void_p': ... - def read_bytes(self, size: int) -> bytes: ... - def read_struct(self, size: int) -> 'struct': ... - - def write_char(self, value: int) -> None: ... - def write_uchar(self, value: int) -> None: ... - def write_short(self, value: int) -> None: ... - def write_ushort(self, value: int) -> None: ... - def write_int(self, value: int) -> None: ... - def write_uint(self, value: int) -> None: ... - def write_long(self, value: int) -> None: ... - def write_ulong(self, value: int) -> None: ... - def write_longlong(self, value: int) -> None: ... - def write_ulonglong(self, value: int) -> None: ... - def write_float(self, value: float) -> None: ... - def write_double(self, value: float) -> None: ... - def write_bool(self, value: bool) -> None: ... - def write_void_p(self, value: 'void_p') -> None: ... - def write_bytes(self, value: bytes) -> None: ... - def write_struct(self, value: 'struct') -> None: ... +class char_p(Pointer[int]): pass +class uchar_p(Pointer[int]): pass +class short_p(Pointer[int]): pass +class ushort_p(Pointer[int]): pass +class int_p(Pointer[int]): pass +class uint_p(Pointer[int]): pass +class long_p(Pointer[int]): pass +class ulong_p(Pointer[int]): pass +class longlong_p(Pointer[int]): pass +class ulonglong_p(Pointer[int]): pass +class float_p(Pointer[float]): pass +class double_p(Pointer[float]): pass +class bool_p(Pointer[bool]): pass class struct: - @overload def __init__(self, size: int): ... - @overload - def __init__(self, buffer: bytes): ... - def addr(self) -> 'void_p': ... def copy(self) -> 'struct': ... def sizeof(self) -> int: ... @@ -79,7 +68,6 @@ class struct: def read_double(self, offset=0) -> float: ... def read_bool(self, offset=0) -> bool: ... def read_void_p(self, offset=0) -> 'void_p': ... - def write_char(self, value: int, offset=0) -> None: ... def write_uchar(self, value: int, offset=0) -> None: ... def write_short(self, value: int, offset=0) -> None: ... @@ -109,48 +97,14 @@ def float_(val: float) -> struct: ... def double_(val: float) -> struct: ... def bool_(val: bool) -> struct: ... -char_p = void_p -uchar_p = void_p -short_p = void_p -ushort_p = void_p -int_p = void_p -uint_p = void_p -long_p = void_p -ulong_p = void_p -longlong_p = void_p -ulonglong_p = void_p -float_p = void_p -double_p = void_p -bool_p = void_p - -class array(struct): - count: int - item_size: int - - def __new__(cls, count: int, item_size: int): ... - def __getitem__(self, index: int) -> struct: ... - def __setitem__(self, index: int, value: struct) -> None: ... - def __len__(self) -> int: ... - -from typing import Generic, TypeVar - -T = TypeVar('T') - class _StructLike(Generic[T]): def to_struct(self) -> struct: ... @classmethod def from_struct(cls, s: struct) -> T: ... - def addr(self) -> '_PointerLike[T]': ... - def sizeof(self) -> int: ... + def addr(self) -> 'Pointer[T]': ... def copy(self) -> T: ... + def sizeof(self) -> int: ... def __eq__(self, other: T) -> bool: ... def __ne__(self, other: T) -> bool: ... -class _PointerLike(Generic[T]): - def __eq__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... - def __hash__(self) -> int: ... - - @property - def _value(self) -> int: ... diff --git a/python/c.py b/python/c.py deleted file mode 100644 index e876c0be..00000000 --- a/python/c.py +++ /dev/null @@ -1,27 +0,0 @@ -class array(struct): - item_count: int - item_size: int - - def __new__(cls, item_count: int, item_size: int = 1): - obj = struct.__new__(cls, item_count * item_size) - obj._enable_instance_dict() - obj.item_count = item_count - obj.item_size = item_size - return obj - - def __getitem__(self, index: int) -> struct: - if index < 0 or index >= self.item_count: - raise IndexError("array index out of range") - p = self.addr() + self.item_size * index - return p.read_struct(self.item_size) - - def __setitem__(self, index: int, value: struct) -> None: - if index < 0 or index >= self.item_count: - raise IndexError("array index out of range") - if value.sizeof() != self.item_size: - raise ValueError(f"array item size mismatch: {value.sizeof()} != {self.item_size}") - p = self.addr() + self.item_size * index - p.write_struct(value) - - def __len__(self) -> int: - return self.item_count diff --git a/src/cffi.cpp b/src/cffi.cpp index 7965f68d..3931a5ef 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -1,5 +1,4 @@ #include "pocketpy/cffi.h" -#include "pocketpy/str.h" namespace pkpy{ @@ -10,27 +9,20 @@ namespace pkpy{ return vm->heap.gcnew(cls, reinterpret_cast(addr)); }); - vm->bind_method<0>(type, "hex", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - return VAR(self.hex()); + vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ + VoidP& self = _CAST(VoidP&, obj); + return reinterpret_cast(self.ptr); }); vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ VoidP& self = _CAST(VoidP&, obj); - std::stringstream ss; - ss << ""; - return VAR(ss.str()); - }); - - vm->bind_property(type, "_value: int", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - return VAR(reinterpret_cast(self.ptr)); + return VAR(fmt("")); }); #define BIND_CMP(name, op) \ - vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ \ - if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return vm->NotImplemented; \ - return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs)); \ + vm->bind##name(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ \ + if(!vm->isinstance(rhs, VoidP::_type(vm))) return vm->NotImplemented; \ + return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs)); \ }); BIND_CMP(__eq__, ==) @@ -40,81 +32,14 @@ namespace pkpy{ BIND_CMP(__ge__, >=) #undef BIND_CMP - - vm->bind__hash__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ - VoidP& self = _CAST(VoidP&, obj); - return reinterpret_cast(self.ptr); - }); - - vm->bind__add__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ - VoidP& self = _CAST(VoidP&, lhs); - i64 offset = CAST(i64, rhs); - return VAR_T(VoidP, (char*)self.ptr + offset); - }); - - vm->bind__sub__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){ - VoidP& self = _CAST(VoidP&, lhs); - i64 offset = CAST(i64, rhs); - return VAR_T(VoidP, (char*)self.ptr - offset); - }); - -#define BIND_SETGET(T, name) \ - vm->bind_method<0>(type, "read_" name, [](VM* vm, ArgsView args){ \ - VoidP& self = _CAST(VoidP&, args[0]); \ - return VAR(*(T*)self.ptr); \ - }); \ - vm->bind_method<1>(type, "write_" 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") - BIND_SETGET(void*, "void_p") - - vm->bind_method<1>(type, "read_bytes", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - i64 size = CAST(i64, args[1]); - std::vector buffer(size); - memcpy(buffer.data(), self.ptr, size); - return VAR(Bytes(std::move(buffer))); - }); - - vm->bind_method<1>(type, "write_bytes", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - Bytes& bytes = CAST(Bytes&, args[1]); - memcpy(self.ptr, bytes.data(), bytes.size()); - return vm->None; - }); - -#undef BIND_SETGET } + void C99Struct::_register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); - if(is_int(args[1])){ - int size = _CAST(int, args[1]); - return vm->heap.gcnew(cls, size); - } - if(is_non_tagged_type(args[1], vm->tp_bytes)){ - const Bytes& b = _CAST(Bytes&, args[1]); - return vm->heap.gcnew(cls, (void*)b.data(), b.size()); - } - vm->TypeError("expected int or bytes"); - return vm->None; + int size = CAST(int, args[1]); + return vm->heap.gcnew(cls, size); }); vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){ @@ -161,7 +86,6 @@ namespace pkpy{ *(T*)ptr = CAST(T, args[1]); \ return vm->None; \ }); - BIND_SETGET(char, "char") BIND_SETGET(unsigned char, "uchar") BIND_SETGET(short, "short") @@ -177,22 +101,6 @@ namespace pkpy{ BIND_SETGET(bool, "bool") BIND_SETGET(void*, "void_p") #undef BIND_SETGET - - // patch VoidP - type = vm->_t(VoidP::_type(vm)); - - vm->bind_method<1>(type, "read_struct", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - int size = CAST(int, args[1]); - return VAR_T(C99Struct, self.ptr, size); - }); - - vm->bind_method<1>(type, "write_struct", [](VM* vm, ArgsView args){ - VoidP& self = _CAST(VoidP&, args[0]); - C99Struct& other = CAST(C99Struct&, args[1]); - memcpy(self.ptr, other.p, other.size); - return vm->None; - }); } void add_module_c(VM* vm){ @@ -225,28 +133,81 @@ void add_module_c(VM* vm){ }); #endif - vm->bind_func<1>(mod, "sizeof", [](VM* vm, ArgsView args){ - const Str& type = CAST(Str&, args[0]); - auto it = _refl_types.find(type.sv()); - if(it != _refl_types.end()) return VAR(it->second.size); - vm->ValueError("not a valid c99 type"); - return vm->None; - }); - VoidP::register_class(vm, mod); C99Struct::register_class(vm, mod); mod->attr().set("NULL", VAR_T(VoidP, nullptr)); - add_refl_type("void_p", sizeof(void*)); - PyObject* void_p_t = mod->attr("void_p"); + vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args){ + VoidP& ptr = CAST(VoidP&, args[0]); + vm->check_non_tagged_type(args[1], vm->tp_type); + Type cls = PK_OBJ_GET(Type, args[1]); + if(!vm->issubclass(cls, VoidP::_type(vm))){ + vm->ValueError("expected a subclass of void_p"); + } + return vm->heap.gcnew(cls, ptr.ptr); + }); -#define BIND_PRIMITIVE(T, name) \ - vm->bind_func<1>(mod, name "_", [](VM* vm, ArgsView args){ \ - T val = CAST(T, args[0]); \ - return VAR_T(C99Struct, &val, sizeof(T)); \ - }); \ - add_refl_type(name, sizeof(T)); \ - mod->attr().set(name "_p", void_p_t); \ + vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args){ + VoidP& ptr = CAST(VoidP&, args[0]); + return VAR(reinterpret_cast(ptr.ptr)); + }); + + vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){ + VoidP& ptr = CAST(VoidP&, args[0]); + void* value = *reinterpret_cast(ptr.ptr); + return vm->heap.gcnew(args[0]->type, value); + }); + + PyObject* type; + Type type_t; + +#define BIND_PRIMITIVE(T, CNAME) \ + vm->bind_func<1>(mod, CNAME "_", [](VM* vm, ArgsView args){ \ + T val = CAST(T, args[0]); \ + return VAR_T(C99Struct, &val, sizeof(T)); \ + }); \ + type = vm->new_type_object(mod, CNAME "_p", VoidP::_type(vm)); \ + type_t = PK_OBJ_GET(Type, type); \ + vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); \ + T* target = (T*)voidp.ptr; \ + return VAR(*target); \ + }); \ + vm->bind_method<1>(type, "write", [](VM* vm, ArgsView args){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); \ + T val = CAST(T, args[1]); \ + T* target = (T*)voidp.ptr; \ + *target = val; \ + return vm->None; \ + }); \ + vm->bind__getitem__(type_t, [](VM* vm, PyObject* obj, PyObject* index){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, obj); \ + i64 offset = CAST(i64, index); \ + T* target = (T*)voidp.ptr; \ + return VAR(target[offset]); \ + }); \ + vm->bind__setitem__(type_t, [](VM* vm, PyObject* obj, PyObject* index, PyObject* value){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, obj); \ + i64 offset = CAST(i64, index); \ + T* target = (T*)voidp.ptr; \ + target[offset] = CAST(T, value); \ + }); \ + vm->bind__add__(type_t, [](VM* vm, PyObject* lhs, PyObject* rhs){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, lhs); \ + i64 offset = CAST(i64, rhs); \ + T* target = (T*)voidp.ptr; \ + return vm->heap.gcnew(lhs->type, target + offset); \ + }); \ + vm->bind__sub__(type_t, [](VM* vm, PyObject* lhs, PyObject* rhs){ \ + VoidP& voidp = PK_OBJ_GET(VoidP, lhs); \ + i64 offset = CAST(i64, rhs); \ + T* target = (T*)voidp.ptr; \ + return vm->heap.gcnew(lhs->type, target - offset); \ + }); \ + vm->bind__repr__(type_t, [](VM* vm, PyObject* obj){ \ + VoidP& self = _CAST(VoidP&, obj); \ + return VAR(fmt("<", CNAME, "* at ", self.hex(), ">")); \ + }); \ BIND_PRIMITIVE(char, "char") BIND_PRIMITIVE(unsigned char, "uchar") @@ -262,9 +223,7 @@ void add_module_c(VM* vm){ BIND_PRIMITIVE(double, "double") BIND_PRIMITIVE(bool, "bool") - // add array type - CodeObject_ code = vm->compile(kPythonLibs["c"], "c.py", EXEC_MODE); - vm->_exec(code, mod); +#undef BIND_PRIMITIVE } } // namespace pkpy \ No newline at end of file diff --git a/src/vm.cpp b/src/vm.cpp index 2eae8853..5a016938 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -79,13 +79,17 @@ namespace pkpy{ return nullptr; } - bool VM::isinstance(PyObject* obj, Type cls_t){ + bool VM::isinstance(PyObject* obj, Type base){ Type obj_t = PK_OBJ_GET(Type, _t(obj)); + return issubclass(obj_t, base); + } + + bool VM::issubclass(Type cls, Type base){ do{ - if(obj_t == cls_t) return true; - Type base = _all_types[obj_t].base; - if(base.index == -1) break; - obj_t = base; + if(cls == base) return true; + Type next = _all_types[cls].base; + if(next.index == -1) break; + cls = next; }while(true); return false; } diff --git a/tests/80_c.py b/tests/80_c.py index 1ddae36b..f61484c6 100644 --- a/tests/80_c.py +++ b/tests/80_c.py @@ -1,33 +1,32 @@ import c -array = c.malloc(c.sizeof("int") * 10) +a = c.malloc(100) +c.free(a) + +a = c.malloc(100) +c.memset(a, 0, 100) +b = c.malloc(100) +b = c.memcpy(b, a, 100) + +bp = c.p_cast(a, c.int_p) + +assert c.p_value(c.NULL) == 0 +assert c.NULL == c.NULL +assert c.NULL != a for i in range(10): - off = c.sizeof("int") * i - (array+off).write_int(i) + bp[i] = i + assert bp[i] == i + (bp+i).write(i) + assert (bp+i).read() == i -x = c.int_(0) -for i in range(10): - off = c.sizeof("int") * i - i = (array+off).read_int() - x.write_int(x.read_int() + i) +i = c.float_(10) +assert i.sizeof() == 4 +j = i.copy() +assert i == j +assert i is not j -assert x.read_int() == (0+9)*10//2 - -c.memset(array, 0, c.sizeof("int") * 10) - -for i in range(10): - off = c.sizeof("int") * i - assert (array+off).read_char() == 0 - -array2 = c.malloc(c.sizeof("int") * 10) -c.memcpy(array2, array, c.sizeof("int") * 10) -for i in range(10): - off = c.sizeof("int") * i - assert (array+off).read_char() == 0 - -c.free(array) -c.free(array2) +#################### class Vec2(c.struct): def __new__(cls, x: float, y: float): @@ -50,4 +49,4 @@ class Vec2(c.struct): a = Vec2(1, 2) assert isinstance(a, c.struct) assert type(a) is Vec2 -assert repr(a) == "Vec2(1.0, 2.0)" +assert repr(a) == "Vec2(1.0, 2.0)" \ No newline at end of file diff --git a/tests/99_cffi_2.py b/tests/99_cffi_2.py deleted file mode 100644 index 17d184a2..00000000 --- a/tests/99_cffi_2.py +++ /dev/null @@ -1,58 +0,0 @@ -import c - -assert c.NULL == c.void_p(0) -# ------------------------------------------------ -# 此处测试并不完全 -c_void_1 = c.malloc(8) -c_void_1.read_bytes(5) -c_void_1.write_bytes(c_void_1.read_bytes(5)) -# ------------------------------------------------ -c_void_1 = c.malloc(32) -my_struct2 = c_void_1.read_struct(32) -assert my_struct2.sizeof() == 32 - -data_bytes = bytes([1,2,3]) -my_struct4 = c.struct(data_bytes) - -try: - c.struct(True) - raise Exception('c.struct 的构造方法未能触发 TypeError("expected int or bytes")') -except TypeError: - pass - -try: - c.struct(1,2,3) - raise Exception('c.struct 的构造方法未能触发 TypeError("expected 1 or 2 arguments")') -except TypeError: - pass -# ------------------------------------------------ -my_struct1 = c.struct(16) -assert my_struct1.sizeof() == 16 - -# 对 c.struct 的 copy 方法的测试不完全 -assert my_struct1.copy().sizeof() == 16 - -data_bytes = bytes([1,2,3]) -my_struct4 = c.struct(data_bytes) -assert my_struct4.addr().read_bytes( - my_struct4.sizeof() -) == data_bytes - - -# ------------------------------------------------ -# 此处测试并不完全 -c_void_1 = c.malloc(16) -my_struct1 = c.struct(16) -c_void_1.write_struct(my_struct1) -assert c_void_1.read_struct(16) == my_struct1 - -from c import array, int_, NULL - -assert NULL._value == 0 - -a = array(10, item_size=4) -assert a.item_count == 10 -assert a.item_size == 4 - -a[4] = int_(123) -assert a[4] == int_(123) \ No newline at end of file