diff --git a/include/pocketpy/cffi.h b/include/pocketpy/cffi.h index 98c7878c..8cdd0598 100644 --- a/include/pocketpy/cffi.h +++ b/include/pocketpy/cffi.h @@ -7,7 +7,7 @@ namespace pkpy { #define PY_CLASS(T, mod, name) \ - static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \ + static Type _type(VM* vm) { return vm->_cxx_typeid_map[&typeid(T)]; } \ static void _check_type(VM* vm, PyObject* val){ \ if(!vm->isinstance(val, T::_type(vm))){ \ vm->TypeError("expected '" #mod "." #name "', got " + _type_name(vm, vm->_tp(val)).escape()); \ @@ -21,7 +21,7 @@ namespace pkpy { } \ PyObject* type = vm->new_type_object(mod, #name, base); \ mod->attr().set(#name, type); \ - vm->_cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type); \ + vm->_cxx_typeid_map[&typeid(T)] = PK_OBJ_GET(Type, type); \ T::_register(vm, mod, type); \ return type; \ } @@ -54,6 +54,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); +} + inline PyObject* py_var(VM* vm, const void* p){ return VAR_T(VoidP, p); } diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index d1b774a7..d3d4a54b 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #define PK_VERSION "1.4.2" @@ -238,4 +238,19 @@ inline const char* kPlatformStrings[] = { #define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?istop; i+=step) +template +inline constexpr bool is_integral_v = std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + +template +inline constexpr bool is_floating_point_v = std::is_same_v || std::is_same_v; + } // namespace pkpy diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 0363a652..3a9f1cec 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -12,6 +12,7 @@ #include "dict.h" #include "profiler.h" + namespace pkpy{ /* Stack manipulation macros */ @@ -40,9 +41,7 @@ namespace pkpy{ } \ template<> inline ctype& _py_cast(VM* vm, PyObject* obj) { \ return PK_OBJ_GET(ctype, obj); \ - } \ - inline PyObject* py_var(VM* vm, const ctype& value) { return vm->heap.gcnew(vm->ptype, value);} \ - inline PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));} + } typedef PyObject* (*BinaryFuncC)(VM*, PyObject*, PyObject*); @@ -142,7 +141,7 @@ public: std::map _cached_codes; // typeid -> Type - std::map _cxx_typeid_map; + std::map _cxx_typeid_map; void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr; @@ -465,6 +464,83 @@ DEF_NATIVE_2(ClassMethod, tp_classmethod) #undef DEF_NATIVE_2 +constexpr std::pair _const_cxx_typeid_map[] = { + {&typeid(Str), VM::tp_str}, + {&typeid(List), VM::tp_list}, + {&typeid(Tuple), VM::tp_tuple}, + {&typeid(Function), VM::tp_function}, + {&typeid(NativeFunc), VM::tp_native_func}, + {&typeid(BoundMethod), VM::tp_bound_method}, + {&typeid(Range), VM::tp_range}, + {&typeid(Slice), VM::tp_slice}, + {&typeid(Exception), VM::tp_exception}, + {&typeid(Bytes), VM::tp_bytes}, + {&typeid(MappingProxy), VM::tp_mappingproxy}, + {&typeid(Dict), VM::tp_dict}, + {&typeid(Property), VM::tp_property}, + {&typeid(StarWrapper), VM::tp_star_wrapper}, + {&typeid(StaticMethod), VM::tp_staticmethod}, + {&typeid(ClassMethod), VM::tp_classmethod}, + /***************************************/ +}; + +template +constexpr Type _find_type_in_const_cxx_typeid_map(){ + for(auto& p : _const_cxx_typeid_map) if(p.first == &typeid(T)) return p.second; + return -1; +} + +template +PyObject* py_var(VM* vm, __T&& value){ + using T = std::decay_t<__T>; + + static_assert(!std::is_same_v, "py_var(VM*, PyObject*) is not allowed"); + + if constexpr(std::is_same_v || std::is_same_v || std::is_same_v){ + // str (shortcuts) + return VAR(Str(std::forward<__T>(value))); + }else if constexpr(std::is_same_v){ + // NoneType + return vm->None; + }else if constexpr(std::is_same_v){ + // bool + return value ? vm->True : vm->False; + }else if constexpr(is_integral_v){ + // int + i64 val = static_cast(std::forward<__T>(value)); + if(val >= Number::kMinSmallInt && val <= Number::kMaxSmallInt){ + val = (val << 2) | 0b10; + return reinterpret_cast(val); + }else{ + return vm->heap.gcnew(vm->tp_int, val); + } + }else if constexpr(is_floating_point_v){ + // float + return tag_float(static_cast(std::forward<__T>(value))); + }else{ + constexpr Type const_type = _find_type_in_const_cxx_typeid_map(); + if constexpr(const_type.index >= 0){ + return vm->heap.gcnew(const_type, std::forward<__T>(value)); + } + } + // dynamic type + auto it = vm->_cxx_typeid_map.find(&typeid(T)); + if(it == vm->_cxx_typeid_map.end()){ +#if __GNUC__ || __clang__ + throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found")); +#elif _MSC_VER + throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found")); +#else + throw std::runtime_error("py_var() failed: T not found"); +#endif + } + return vm->heap.gcnew(it->second, std::forward<__T>(value)); +} + + + + + #define PY_CAST_INT(T) \ template<> inline T py_cast(VM* vm, PyObject* obj){ \ if(is_small_int(obj)) return (T)(PK_BITS(obj) >> 2); \ @@ -509,41 +585,6 @@ template<> inline double _py_cast(VM* vm, PyObject* obj){ return py_cast(vm, obj); } -#define PY_VAR_INT(T) \ - inline PyObject* py_var(VM* vm, T _val){ \ - i64 val = static_cast(_val); \ - if(val >= Number::kMinSmallInt && val <= Number::kMaxSmallInt){ \ - val = (val << 2) | 0b10; \ - return reinterpret_cast(val); \ - }else{ \ - return vm->heap.gcnew(vm->tp_int, val); \ - } \ - } - -PY_VAR_INT(char) -PY_VAR_INT(short) -PY_VAR_INT(int) -PY_VAR_INT(long) -PY_VAR_INT(long long) -PY_VAR_INT(unsigned char) -PY_VAR_INT(unsigned short) -PY_VAR_INT(unsigned int) -PY_VAR_INT(unsigned long) -PY_VAR_INT(unsigned long long) -#undef PY_VAR_INT - -inline PyObject* py_var(VM* vm, float _val){ - return tag_float(static_cast(_val)); -} - -inline PyObject* py_var(VM* vm, double _val){ - return tag_float(static_cast(_val)); -} - -inline PyObject* py_var(VM* vm, bool val){ - return val ? vm->True : vm->False; -} - template<> inline bool py_cast(VM* vm, PyObject* obj){ if(obj == vm->True) return true; if(obj == vm->False) return false; @@ -563,10 +604,6 @@ template<> inline CString _py_cast(VM* vm, PyObject* obj){ return PK_OBJ_GET(Str, obj).c_str(); } -inline PyObject* py_var(VM* vm, const char* val){ - return VAR(Str(val)); -} - template<> inline const char* py_cast(VM* vm, PyObject* obj){ if(obj == vm->None) return nullptr; @@ -579,18 +616,6 @@ inline const char* _py_cast(VM* vm, PyObject* obj){ return PK_OBJ_GET(Str, obj).c_str(); } -inline PyObject* py_var(VM* vm, std::string val){ - return VAR(Str(val)); -} - -inline PyObject* py_var(VM* vm, std::string_view val){ - return VAR(Str(val)); -} - -inline PyObject* py_var(VM* vm, NoReturn val){ - return vm->None; -} - template PyObject* VM::bind_method(Type type, Str name, NativeFuncC fn) { PyObject* nf = VAR(NativeFunc(fn, ARGC, true));