object.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #pragma once
  2. #include "instance.h"
  3. namespace pybind11 {
  4. template <typename Derived>
  5. class interface {
  6. private:
  7. pkpy::PyVar ptr() const { return static_cast<const Derived*>(this)->ptr(); }
  8. public:
  9. bool is_none() const {
  10. #if PK_VERSION_MAJOR == 2
  11. return ptr().operator== (vm->None.get());
  12. #else
  13. return ptr() == vm->None;
  14. #endif
  15. }
  16. bool is(const interface& other) const {
  17. #if PK_VERSION_MAJOR == 2
  18. return ptr().operator== (other.ptr().get());
  19. #else
  20. return ptr() == other.ptr();
  21. #endif
  22. }
  23. bool in(const interface& other) const {
  24. return pybind11::cast<bool>(vm->call(vm->py_op("contains"), other.ptr(), ptr()));
  25. }
  26. bool contains(const interface& other) const {
  27. return pybind11::cast<bool>(vm->call(vm->py_op("contains"), ptr(), other.ptr()));
  28. }
  29. protected:
  30. attr_accessor attr(pkpy::StrName key) const;
  31. public:
  32. iterator begin() const;
  33. iterator end() const;
  34. attr_accessor attr(const char* key) const;
  35. attr_accessor attr(const handle& key) const;
  36. attr_accessor doc() const;
  37. item_accessor operator[] (int index) const;
  38. item_accessor operator[] (const char* key) const;
  39. item_accessor operator[] (const handle& key) const;
  40. args_proxy operator* () const;
  41. object operator- () const;
  42. object operator~() const;
  43. template <return_value_policy policy = return_value_policy::automatic, typename... Args>
  44. object operator() (Args&&... args) const;
  45. str package() const;
  46. str name() const;
  47. str repr() const;
  48. public:
  49. template <typename T>
  50. T cast() const {
  51. return pybind11::cast<T>(ptr());
  52. }
  53. // this is a internal function, use to interact with pocketpy python
  54. template <typename T>
  55. decltype(auto) _as() const {
  56. static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
  57. #if PK_VERSION_MAJOR == 2
  58. if constexpr(pkpy::is_sso_v<T>) {
  59. return pkpy::_py_cast<T>(vm, ptr());
  60. } else {
  61. return ptr().template obj_get<T>();
  62. }
  63. #else
  64. return (((pkpy::Py_<T>*)ptr())->_value);
  65. #endif
  66. }
  67. };
  68. /// a lightweight wrapper for python objects
  69. class handle : public interface<handle> {
  70. protected:
  71. mutable pkpy::PyVar m_ptr = nullptr;
  72. public:
  73. handle() = default;
  74. handle(const handle& h) = default;
  75. handle& operator= (const handle& other) = default;
  76. handle(std::nullptr_t) = delete;
  77. handle(pkpy::PyVar ptr) : m_ptr(ptr) {}
  78. #if PK_VERSION_MAJOR == 2
  79. handle(pkpy::PyObject* ptr) : m_ptr(ptr) {}
  80. #endif
  81. pkpy::PyVar ptr() const { return m_ptr; }
  82. explicit operator bool () const { return m_ptr != nullptr; }
  83. };
  84. // a helper class to visit type
  85. struct type_visitor {
  86. template <typename T>
  87. constexpr static bool is_type = std::is_same_v<pkpy::Type, std::decay_t<decltype(T::type_or_check())>>;
  88. template <typename T>
  89. static pkpy::Type type() {
  90. if constexpr(is_pyobject_v<T>) {
  91. if constexpr(is_type<T>) {
  92. // for some type, they have according type in python, e.g. bool, int, float
  93. // so just return the according type
  94. return T::type_or_check();
  95. } else {
  96. // for other type, they don't have according type in python, like iterable, iterator
  97. static_assert(dependent_false<T>, "type_or_check not defined");
  98. }
  99. } else {
  100. #if PK_VERSION_MAJOR == 2
  101. // for C++ type, lookup the type in the type map
  102. auto type = vm->_cxx_typeid_map.try_get(typeid(T));
  103. // if found, return the type
  104. if(type) return *type;
  105. #else
  106. auto result = vm->_cxx_typeid_map.find(typeid(T));
  107. if(result != vm->_cxx_typeid_map.end()) { return result->second; }
  108. #endif
  109. // if not found, raise error
  110. std::string msg = "can not c++ instance cast to object, type: {";
  111. msg += type_name<T>();
  112. msg += "} is not registered.";
  113. vm->TypeError(msg);
  114. PK_UNREACHABLE();
  115. }
  116. }
  117. template <typename T, typename Base = void>
  118. static handle create(const handle& scope, const char* name, bool is_builtin = false) {
  119. pkpy::Type type = vm->tp_object;
  120. #if PK_VERSION_MAJOR == 2
  121. pkpy::PyTypeInfo::Vt vt = pkpy::PyTypeInfo::Vt::get<instance>();
  122. if(is_builtin) { vt = pkpy::PyTypeInfo::Vt::get<T>(); }
  123. if constexpr(!std::is_same_v<Base, void>) {
  124. type = type_visitor::type<Base>();
  125. vt = {};
  126. }
  127. handle result = vm->new_type_object(scope.ptr().get(), name, type, true, vt);
  128. if(!is_builtin) { vm->_cxx_typeid_map.insert(typeid(T), result._as<pkpy::Type>()); }
  129. #else
  130. if constexpr(!std::is_same_v<Base, void>) { type = type_visitor::type<Base>(); }
  131. handle result = vm->new_type_object(scope.ptr(), name, type, true);
  132. if(!is_builtin) (vm->_cxx_typeid_map.try_emplace(typeid(T), result._as<pkpy::Type>()));
  133. #endif
  134. // set __module__
  135. setattr(scope, name, result);
  136. return result;
  137. }
  138. template <typename T>
  139. static bool check(const handle& obj) {
  140. if constexpr(is_pyobject_v<T>) {
  141. if constexpr(is_type<T>) {
  142. return vm->isinstance(obj.ptr(), T::type_or_check());
  143. } else {
  144. // some type, like iterable, iterator, they don't have according type in python
  145. // but they have a function to check the type, then just call the function
  146. return T::type_or_check(obj);
  147. }
  148. } else {
  149. return vm->isinstance(obj.ptr(), type<T>());
  150. }
  151. }
  152. };
  153. // undef in pybind11.h
  154. #define PYBIND11_TYPE_IMPLEMENT(parent, name, tp) \
  155. \
  156. private: \
  157. using underlying_type = name; \
  158. \
  159. inline static auto type_or_check = [] { \
  160. return tp; \
  161. }; \
  162. \
  163. decltype(auto) self() const { return _as<underlying_type>(); } \
  164. \
  165. template <typename... Args> \
  166. static handle create(Args&&... args) { \
  167. if constexpr(pkpy::is_sso_v<underlying_type>) { \
  168. return pkpy::py_var(vm, std::forward<Args>(args)...); \
  169. } else { \
  170. return vm->heap.gcnew<underlying_type>(type_or_check(), std::forward<Args>(args)...); \
  171. } \
  172. } \
  173. \
  174. friend type_visitor; \
  175. using parent::parent;
  176. /*=============================================================================//
  177. // pkpy does not use reference counts, so object is just fot API compatibility //
  178. //=============================================================================*/
  179. class object : public handle {
  180. PYBIND11_TYPE_IMPLEMENT(handle, empty, vm->tp_object);
  181. public:
  182. object(const handle& h) : handle(h) {
  183. // object is must not null ptr
  184. assert(h.ptr() != nullptr);
  185. }
  186. };
  187. // undef after usage
  188. #define PYBIND11_BINARY_OPERATOR(OP, NAME) \
  189. inline object operator OP (const handle& lhs, const handle& rhs) { return handle(vm->py_op(NAME))(lhs, rhs); }
  190. #define PYBIND11_INPLACE_OPERATOR(OP, NAME) \
  191. inline object operator OP (handle& lhs, const handle& rhs) { \
  192. handle result = handle(vm->py_op(NAME))(lhs, rhs); \
  193. return lhs = result; \
  194. }
  195. #define PYBIND11_BINARY_LOGIC_OPERATOR(OP, NAME) \
  196. inline bool operator OP (const handle& lhs, const handle& rhs) { \
  197. return pybind11::cast<bool>(handle(vm->py_op(NAME))(lhs, rhs)); \
  198. }
  199. PYBIND11_BINARY_OPERATOR(+, "add");
  200. PYBIND11_BINARY_OPERATOR(-, "sub");
  201. PYBIND11_BINARY_OPERATOR(*, "mul");
  202. PYBIND11_BINARY_OPERATOR(/, "truediv");
  203. PYBIND11_BINARY_OPERATOR(%, "mod");
  204. PYBIND11_BINARY_OPERATOR(|, "or_");
  205. PYBIND11_BINARY_OPERATOR(&, "and_");
  206. PYBIND11_BINARY_OPERATOR(^, "xor");
  207. PYBIND11_BINARY_OPERATOR(<<, "lshift");
  208. PYBIND11_BINARY_OPERATOR(>>, "rshift");
  209. PYBIND11_INPLACE_OPERATOR(+=, "iadd");
  210. PYBIND11_INPLACE_OPERATOR(-=, "isub");
  211. PYBIND11_INPLACE_OPERATOR(*=, "imul");
  212. PYBIND11_INPLACE_OPERATOR(/=, "itruediv");
  213. PYBIND11_INPLACE_OPERATOR(%=, "imod");
  214. PYBIND11_INPLACE_OPERATOR(|=, "ior");
  215. PYBIND11_INPLACE_OPERATOR(&=, "iand");
  216. PYBIND11_INPLACE_OPERATOR(^=, "ixor");
  217. PYBIND11_INPLACE_OPERATOR(<<=, "ilshift");
  218. PYBIND11_INPLACE_OPERATOR(>>=, "irshift");
  219. PYBIND11_BINARY_LOGIC_OPERATOR(==, "eq");
  220. PYBIND11_BINARY_LOGIC_OPERATOR(!=, "ne");
  221. PYBIND11_BINARY_LOGIC_OPERATOR(<, "lt");
  222. PYBIND11_BINARY_LOGIC_OPERATOR(>, "gt");
  223. PYBIND11_BINARY_LOGIC_OPERATOR(<=, "le");
  224. PYBIND11_BINARY_LOGIC_OPERATOR(>=, "ge");
  225. #undef PYBIND11_BINARY_OPERATOR
  226. #undef PYBIND11_INPLACE_OPERATOR
  227. #undef PYBIND11_BINARY_LOGIC_OPERATOR
  228. }; // namespace pybind11