builtins.h 6.6 KB

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