object.h 11 KB

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