#pragma once #include "common.h" #include "namedict.h" #include "tuplelist.h" namespace pkpy { struct Frame; class VM; #if PK_ENABLE_STD_FUNCTION using NativeFuncC = std::function; #else typedef PyObject* (*NativeFuncC)(VM*, ArgsView); #endif struct BoundMethod { PyObject* self; PyObject* func; BoundMethod(PyObject* self, PyObject* func) : self(self), func(func) {} bool operator==(const BoundMethod& rhs) const noexcept { return self == rhs.self && func == rhs.func; } bool operator!=(const BoundMethod& rhs) const noexcept { return self != rhs.self || func != rhs.func; } }; struct Property{ PyObject* getter; PyObject* setter; Property(PyObject* getter, PyObject* setter) : getter(getter), setter(setter) {} }; struct Range { i64 start = 0; i64 stop = -1; i64 step = 1; }; struct StarWrapper{ int level; // either 1 or 2 PyObject* obj; StarWrapper(int level, PyObject* obj) : level(level), obj(obj) {} }; struct Bytes{ std::vector _data; bool _ok; int size() const noexcept { return _data.size(); } int operator[](int i) const noexcept { return (int)(uint8_t)_data[i]; } const char* data() const noexcept { return _data.data(); } bool operator==(const Bytes& rhs) const noexcept { return _data == rhs._data; } bool operator!=(const Bytes& rhs) const noexcept { return _data != rhs._data; } Str str() const noexcept { return Str(_data.data(), _data.size()); } Bytes() : _data(), _ok(false) {} Bytes(std::vector&& data) : _data(std::move(data)), _ok(true) {} Bytes(const Str& data) : _data(data.begin(), data.end()), _ok(true) {} Bytes(std::string_view sv): _data(sv.begin(), sv.end()), _ok(true) {} operator bool() const noexcept { return _ok; } }; using Super = std::pair; struct Slice { PyObject* start; PyObject* stop; PyObject* step; Slice(PyObject* start, PyObject* stop, PyObject* step) : start(start), stop(stop), step(step) {} }; struct GCHeader { bool enabled; // whether this object is managed by GC bool marked; // whether this object is marked GCHeader() : enabled(true), marked(false) {} }; struct PyObject{ GCHeader gc; Type type; NameDict* _attr; bool is_attr_valid() const noexcept { return _attr != nullptr; } NameDict& attr() noexcept { return *_attr; } PyObject* attr(StrName name) const noexcept { return (*_attr)[name]; } virtual void _obj_gc_mark() = 0; PyObject(Type type) : type(type), _attr(nullptr) {} virtual ~PyObject(); void enable_instance_dict(float lf=kInstAttrLoadFactor) { _attr = new(pool64.alloc()) NameDict(lf); } }; template struct has_gc_marker : std::false_type {}; template struct has_gc_marker> : std::true_type {}; template struct Py_ final: PyObject { T _value; void _obj_gc_mark() override { if constexpr (has_gc_marker::value) { _value._gc_mark(); } } Py_(Type type, const T& value) : PyObject(type), _value(value) {} Py_(Type type, T&& value) : PyObject(type), _value(std::move(value)) {} }; struct MappingProxy{ PyObject* obj; MappingProxy(PyObject* obj) : obj(obj) {} NameDict& attr() noexcept { return obj->attr(); } }; #define PK_OBJ_GET(T, obj) (((Py_*)(obj))->_value) #define PK_OBJ_MARK(obj) \ if(!is_tagged(obj) && !(obj)->gc.marked) { \ (obj)->gc.marked = true; \ (obj)->_obj_gc_mark(); \ if((obj)->is_attr_valid()) gc_mark_namedict((obj)->attr()); \ } inline void gc_mark_namedict(NameDict& t){ if(t.size() == 0) return; for(uint16_t i=0; i") #else DEF_SNAME(__name__); #define OBJ_NAME(obj) PK_OBJ_GET(Str, vm->getattr(obj, __name__)) #endif const int kTpIntIndex = 2; const int kTpFloatIndex = 3; inline bool is_type(PyObject* obj, Type type) { #if PK_DEBUG_EXTRA_CHECK if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr"); if(is_special(obj)) throw std::runtime_error("is_type() called with special object"); #endif switch(type.index){ case kTpIntIndex: return is_int(obj); case kTpFloatIndex: return is_float(obj); default: return !is_tagged(obj) && obj->type == type; } } inline bool is_non_tagged_type(PyObject* obj, Type type) { #if PK_DEBUG_EXTRA_CHECK if(obj == nullptr) throw std::runtime_error("is_non_tagged_type() called with nullptr"); if(is_special(obj)) throw std::runtime_error("is_non_tagged_type() called with special object"); #endif return !is_tagged(obj) && obj->type == type; } union BitsCvt { i64 _int; f64 _float; BitsCvt(i64 val) : _int(val) {} BitsCvt(f64 val) : _float(val) {} }; template struct is_py_class : std::false_type {}; template struct is_py_class> : std::true_type {}; template T to_void_p(VM*, PyObject*); template T to_c99_struct(VM*, PyObject*); template __T py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; if constexpr(std::is_enum_v){ return (__T)py_cast(vm, obj); }else if constexpr(std::is_pointer_v){ return to_void_p(vm, obj); }else if constexpr(is_py_class::value){ T::_check_type(vm, obj); return PK_OBJ_GET(T, obj); }else if constexpr(std::is_pod_v){ return to_c99_struct(vm, obj); }else { return Discarded(); } } template __T _py_cast(VM* vm, PyObject* obj) { using T = std::decay_t<__T>; if constexpr(std::is_enum_v){ return (__T)_py_cast(vm, obj); }else if constexpr(std::is_pointer_v<__T>){ return to_void_p<__T>(vm, obj); }else if constexpr(is_py_class::value){ return PK_OBJ_GET(T, obj); }else if constexpr(std::is_pod_v){ return to_c99_struct(vm, obj); }else { return Discarded(); } } #define VAR(x) py_var(vm, x) #define CAST(T, x) py_cast(vm, x) #define _CAST(T, x) _py_cast(vm, x) #define CAST_F(x) py_cast(vm, x) #define CAST_DEFAULT(T, x, default_value) (x != vm->None) ? py_cast(vm, x) : (default_value) /*****************************************************************/ template<> struct Py_ final: PyObject { List _value; Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {} Py_(Type type, const List& val): PyObject(type), _value(val) {} void _obj_gc_mark() override { for(PyObject* obj: _value) PK_OBJ_MARK(obj); } }; template<> struct Py_ final: PyObject { Tuple _value; Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {} Py_(Type type, const Tuple& val): PyObject(type), _value(val) {} void _obj_gc_mark() override { for(PyObject* obj: _value) PK_OBJ_MARK(obj); } }; template<> struct Py_ final: PyObject { MappingProxy _value; Py_(Type type, MappingProxy val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.obj); } }; template<> struct Py_ final: PyObject { BoundMethod _value; Py_(Type type, BoundMethod val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.self); PK_OBJ_MARK(_value.func); } }; template<> struct Py_ final: PyObject { StarWrapper _value; Py_(Type type, StarWrapper val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.obj); } }; template<> struct Py_ final: PyObject { Property _value; Py_(Type type, Property val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.getter); PK_OBJ_MARK(_value.setter); } }; template<> struct Py_ final: PyObject { Slice _value; Py_(Type type, Slice val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.start); PK_OBJ_MARK(_value.stop); PK_OBJ_MARK(_value.step); } }; template<> struct Py_ final: PyObject { Super _value; Py_(Type type, Super val): PyObject(type), _value(val) {} void _obj_gc_mark() override { PK_OBJ_MARK(_value.first); } }; template<> struct Py_ final: PyObject { Py_(Type type, DummyInstance val): PyObject(type) { PK_UNUSED(val); enable_instance_dict(); } void _obj_gc_mark() override {} }; template<> struct Py_ final: PyObject { Type _value; Py_(Type type, Type val): PyObject(type), _value(val) { enable_instance_dict(kTypeAttrLoadFactor); } void _obj_gc_mark() override {} }; template<> struct Py_ final: PyObject { Py_(Type type, DummyModule val): PyObject(type) { PK_UNUSED(val); enable_instance_dict(kTypeAttrLoadFactor); } void _obj_gc_mark() override {} }; } // namespace pkpy