builtins.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. template <typename T>
  65. constexpr inline bool is_pyobject_v =
  66. std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;
  67. template <typename T>
  68. inline type type::of() {
  69. if constexpr(is_pyobject_v<T>) {
  70. if constexpr(is_check_v<T>) {
  71. return type(tp_object);
  72. } else {
  73. return type(T::type_or_check());
  74. }
  75. } else {
  76. auto it = m_type_map.find(typeid(T));
  77. if(it != m_type_map.end()) {
  78. return type(it->second);
  79. } else {
  80. // if not found, raise error
  81. std::string msg = "can not c++ instance cast to object, type: {";
  82. msg += type_name<T>();
  83. msg += "} is not registered.";
  84. throw std::runtime_error(msg);
  85. }
  86. }
  87. }
  88. template <typename T>
  89. inline bool type::isinstance(handle obj) {
  90. if constexpr(is_pyobject_v<T>) {
  91. // for every python object wrapper type, there must be a `type_or_check` method.
  92. // for some types, it returns the underlying type in pkpy, e.g., `int_` -> `tp_int`.
  93. // for other types that may not have a corresponding type in pkpy, it returns a check
  94. // function. e.g., `iterable` -> `[](handle h){ return hasattr(h, "iter"); }`.
  95. auto type_or_check = T::type_or_check();
  96. if constexpr(is_check_v<T>) {
  97. return type_or_check(obj);
  98. } else {
  99. return pkbind::isinstance(obj, type(type_or_check));
  100. }
  101. } else {
  102. return pkbind::isinstance(obj, of<T>());
  103. }
  104. }
  105. inline bool issubclass(type derived, type base) {
  106. return py_issubclass(derived.index(), base.index());
  107. }
  108. template <typename T>
  109. inline bool isinstance(handle obj) {
  110. return type::isinstance<T>(obj);
  111. }
  112. template <>
  113. inline bool isinstance<handle>(handle) = delete;
  114. template <typename T, typename SFINAE = void>
  115. struct type_caster;
  116. template <typename T>
  117. object cast(T&& value,
  118. return_value_policy policy = return_value_policy::automatic_reference,
  119. handle parent = {}) {
  120. // decay_t can resolve c-array type, but remove_cv_ref_t can't.
  121. using underlying_type = std::decay_t<T>;
  122. if constexpr(std::is_convertible_v<underlying_type, handle> &&
  123. !is_pyobject_v<underlying_type>) {
  124. return object(std::forward<T>(value), object::realloc_t{});
  125. } else if constexpr(is_unique_pointer_v<underlying_type>) {
  126. using pointer = typename underlying_type::pointer;
  127. return type_caster<pointer>::cast(value.release(),
  128. return_value_policy::take_ownership,
  129. parent);
  130. } else {
  131. static_assert(!is_multiple_pointer_v<underlying_type>,
  132. "multiple pointer is not supported.");
  133. static_assert(!std::is_void_v<std::remove_pointer_t<underlying_type>>,
  134. "void* is not supported, consider using py::capsule.");
  135. // resolve for automatic policy.
  136. if(policy == return_value_policy::automatic) {
  137. policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
  138. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  139. : return_value_policy::move;
  140. } else if(policy == return_value_policy::automatic_reference) {
  141. policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
  142. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  143. : return_value_policy::move;
  144. }
  145. return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
  146. }
  147. }
  148. template <typename T>
  149. T cast(handle obj, bool convert = true) {
  150. using caster_t = type_caster<T>;
  151. constexpr auto is_dangling_v =
  152. (std::is_reference_v<T> || is_pointer_v<T>) && caster_t::is_temporary_v;
  153. static_assert(!is_dangling_v, "dangling reference or pointer is not allowed.");
  154. assert(obj.ptr() != nullptr);
  155. caster_t caster;
  156. if(caster.load(obj, convert)) {
  157. if constexpr(std::is_reference_v<T>) {
  158. return caster.value();
  159. } else {
  160. return std::move(caster.value());
  161. }
  162. } else {
  163. std::string msg = "cast python instance to c++ failed, obj type is: {";
  164. msg += type::of(obj).name();
  165. msg += "}, target type is: {";
  166. msg += type_name<T>();
  167. msg += "}.";
  168. throw cast_error(msg);
  169. }
  170. }
  171. template <typename Derived>
  172. template <typename T>
  173. T interface<Derived>::cast() const {
  174. return pkbind::cast<T>(handle(this->ptr()), true);
  175. }
  176. } // namespace pkbind