builtins.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #pragma once
  2. #include "types.h"
  3. namespace pkbind {
  4. template <typename... Args>
  5. inline void print(Args&&... args) {
  6. handle print = py_getbuiltin(py_name("print"));
  7. print(std::forward<Args>(args)...);
  8. }
  9. inline object eval(std::string_view code, handle globals = none(), handle locals = none()) {
  10. if(globals.is_none() && locals.is_none()) {
  11. std::string src{code};
  12. raise_call<py_eval>(src.c_str(), nullptr);
  13. return object::from_ret();
  14. } else {
  15. handle eval = py_getbuiltin(py_name("eval"));
  16. return eval(str(code),
  17. globals.is_none() ? dict() : globals,
  18. locals.is_none() ? dict() : locals);
  19. }
  20. }
  21. inline object exec(std::string_view code, handle globals = none(), handle locals = none()) {
  22. if(globals.is_none() && locals.is_none()) {
  23. std::string src{code};
  24. raise_call<py_exec>(src.c_str(), "exec", EXEC_MODE, nullptr);
  25. return object::from_ret();
  26. } else {
  27. handle exec = py_getbuiltin(py_name("exec"));
  28. return exec(str(code), globals, locals);
  29. }
  30. }
  31. inline object locals() {
  32. handle locals = py_getbuiltin(py_name("locals"));
  33. return locals();
  34. }
  35. inline object globals() {
  36. handle globals = py_getbuiltin(py_name("globals"));
  37. return globals();
  38. }
  39. inline bool hasattr(handle obj, name name) {
  40. auto pc = py_peek(0);
  41. auto result = py_getattr(obj.ptr(), name.index());
  42. if(result) {
  43. return true;
  44. } else {
  45. py_clearexc(pc);
  46. return false;
  47. }
  48. }
  49. inline object getattr(handle obj, name name) {
  50. raise_call<py_getattr>(obj.ptr(), name.index());
  51. return object::from_ret();
  52. }
  53. inline void setattr(handle obj, name name, handle value) {
  54. raise_call<py_setattr>(obj.ptr(), name.index(), value.ptr());
  55. }
  56. inline void delattr(handle obj, name name) { raise_call<py_delattr>(obj.ptr(), name.index()); }
  57. inline py_i64 hash(handle obj) {
  58. py_i64 result = 0;
  59. raise_call<py_hash>(obj.ptr(), &result);
  60. return result;
  61. }
  62. inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), type.index()); }
  63. inline bool python_error::match(type type) const { return isinstance(m_exception.ptr(), type); }
  64. inline bool error_already_set::match(type type) const { return py_matchexc(type.index()); }
  65. template <typename T>
  66. constexpr inline bool is_pyobject_v =
  67. std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;
  68. template <typename T>
  69. inline type type::of() {
  70. if constexpr(is_pyobject_v<T>) {
  71. if constexpr(is_check_v<T>) {
  72. return type(tp_object);
  73. } else {
  74. return type(T::type_or_check());
  75. }
  76. } else {
  77. auto it = m_type_map.find(typeid(T));
  78. if(it != m_type_map.end()) {
  79. return type(it->second);
  80. } else {
  81. // if not found, raise error
  82. std::string msg = "can not c++ instance cast to object, type: {";
  83. msg += type_name<T>();
  84. msg += "} is not registered.";
  85. throw std::runtime_error(msg);
  86. }
  87. }
  88. }
  89. template <typename T>
  90. inline bool type::isinstance(handle obj) {
  91. if constexpr(is_pyobject_v<T>) {
  92. // for every python object wrapper type, there must be a `type_or_check` method.
  93. // for some types, it returns the underlying type in pkpy, e.g., `int_` -> `tp_int`.
  94. // for other types that may not have a corresponding type in pkpy, it returns a check
  95. // function. e.g., `iterable` -> `[](handle h){ return hasattr(h, "iter"); }`.
  96. auto type_or_check = T::type_or_check();
  97. if constexpr(is_check_v<T>) {
  98. return type_or_check(obj);
  99. } else {
  100. return pkbind::isinstance(obj, type(type_or_check));
  101. }
  102. } else {
  103. return pkbind::isinstance(obj, of<T>());
  104. }
  105. }
  106. inline bool issubclass(type derived, type base) {
  107. return py_issubclass(derived.index(), base.index());
  108. }
  109. template <typename T>
  110. inline bool isinstance(handle obj) {
  111. return type::isinstance<T>(obj);
  112. }
  113. template <>
  114. inline bool isinstance<handle>(handle) = delete;
  115. template <typename T, typename SFINAE = void>
  116. struct type_caster;
  117. template <typename T>
  118. object cast(T&& value,
  119. return_value_policy policy = return_value_policy::automatic_reference,
  120. handle parent = {}) {
  121. // decay_t can resolve c-array type, but remove_cv_ref_t can't.
  122. using underlying_type = std::decay_t<T>;
  123. if constexpr(std::is_convertible_v<underlying_type, handle> &&
  124. !is_pyobject_v<underlying_type>) {
  125. return object(std::forward<T>(value), object::realloc_t{});
  126. } else if constexpr(is_unique_pointer_v<underlying_type>) {
  127. using pointer = typename underlying_type::pointer;
  128. return type_caster<pointer>::cast(value.release(),
  129. return_value_policy::take_ownership,
  130. parent);
  131. } else {
  132. static_assert(!is_multiple_pointer_v<underlying_type>,
  133. "multiple pointer is not supported.");
  134. static_assert(!std::is_void_v<std::remove_pointer_t<underlying_type>>,
  135. "void* is not supported, consider using py::capsule.");
  136. // resolve for automatic policy.
  137. if(policy == return_value_policy::automatic) {
  138. policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
  139. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  140. : return_value_policy::move;
  141. } else if(policy == return_value_policy::automatic_reference) {
  142. policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
  143. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  144. : return_value_policy::move;
  145. }
  146. return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
  147. }
  148. }
  149. template <typename T>
  150. T cast(handle obj, bool convert = true) {
  151. using caster_t = type_caster<T>;
  152. constexpr auto is_dangling_v =
  153. (std::is_reference_v<T> || is_pointer_v<T>) && caster_t::is_temporary_v;
  154. static_assert(!is_dangling_v, "dangling reference or pointer is not allowed.");
  155. assert(obj.ptr() != nullptr);
  156. caster_t caster;
  157. if(caster.load(obj, convert)) {
  158. if constexpr(std::is_reference_v<T>) {
  159. return caster.value();
  160. } else {
  161. return std::move(caster.value());
  162. }
  163. } else {
  164. std::string msg = "cast python instance to c++ failed, obj type is: {";
  165. msg += type::of(obj).name();
  166. msg += "}, target type is: {";
  167. msg += type_name<T>();
  168. msg += "}.";
  169. throw cast_error(msg);
  170. }
  171. }
  172. template <typename Derived>
  173. template <typename T>
  174. T interface<Derived>::cast() const {
  175. return pkbind::cast<T>(handle(this->ptr()), true);
  176. }
  177. } // namespace pkbind