| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- #pragma once
- #include "types.h"
- namespace pkbind {
- template <typename... Args>
- inline void print(Args&&... args) {
- handle print = py_getbuiltin(py_name("print"));
- print(std::forward<Args>(args)...);
- }
- inline object eval(std::string_view code, handle globals = none(), handle locals = none()) {
- if(globals.is_none() && locals.is_none()) {
- std::string src{code};
- raise_call<py_eval>(src.c_str(), nullptr);
- return object::from_ret();
- } else {
- handle eval = py_getbuiltin(py_name("eval"));
- return eval(str(code),
- globals.is_none() ? dict() : globals,
- locals.is_none() ? dict() : locals);
- }
- }
- inline object exec(std::string_view code, handle globals = none(), handle locals = none()) {
- if(globals.is_none() && locals.is_none()) {
- std::string src{code};
- raise_call<py_exec>(src.c_str(), "exec", EXEC_MODE, nullptr);
- return object::from_ret();
- } else {
- handle exec = py_getbuiltin(py_name("exec"));
- return exec(str(code), globals, locals);
- }
- }
- inline object locals() {
- handle locals = py_getbuiltin(py_name("locals"));
- return locals();
- }
- inline object globals() {
- handle globals = py_getbuiltin(py_name("globals"));
- return globals();
- }
- inline bool hasattr(handle obj, name name) {
- auto pc = py_peek(0);
- auto result = py_getattr(obj.ptr(), name.index());
- if(result) {
- return true;
- } else {
- py_clearexc(pc);
- return false;
- }
- }
- inline object getattr(handle obj, name name) {
- raise_call<py_getattr>(obj.ptr(), name.index());
- return object::from_ret();
- }
- inline void setattr(handle obj, name name, handle value) {
- raise_call<py_setattr>(obj.ptr(), name.index(), value.ptr());
- }
- inline void delattr(handle obj, name name) { raise_call<py_delattr>(obj.ptr(), name.index()); }
- inline py_i64 hash(handle obj) {
- py_i64 result = 0;
- raise_call<py_hash>(obj.ptr(), &result);
- return result;
- }
- inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), type.index()); }
- inline bool python_error::match(type type) const { return isinstance(m_exception.ptr(), type); }
- inline bool error_already_set::match(type type) const { return py_matchexc(type.index()); }
- template <typename T>
- constexpr inline bool is_pyobject_v =
- std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;
- template <typename T>
- inline type type::of() {
- if constexpr(is_pyobject_v<T>) {
- if constexpr(is_check_v<T>) {
- return type(tp_object);
- } else {
- return type(T::type_or_check());
- }
- } else {
- auto it = m_type_map.find(typeid(T));
- if(it != m_type_map.end()) {
- return type(it->second);
- } else {
- // if not found, raise error
- std::string msg = "can not c++ instance cast to object, type: {";
- msg += type_name<T>();
- msg += "} is not registered.";
- throw std::runtime_error(msg);
- }
- }
- }
- template <typename T>
- inline bool type::isinstance(handle obj) {
- if constexpr(is_pyobject_v<T>) {
- // for every python object wrapper type, there must be a `type_or_check` method.
- // for some types, it returns the underlying type in pkpy, e.g., `int_` -> `tp_int`.
- // for other types that may not have a corresponding type in pkpy, it returns a check
- // function. e.g., `iterable` -> `[](handle h){ return hasattr(h, "iter"); }`.
- auto type_or_check = T::type_or_check();
- if constexpr(is_check_v<T>) {
- return type_or_check(obj);
- } else {
- return pkbind::isinstance(obj, type(type_or_check));
- }
- } else {
- return pkbind::isinstance(obj, of<T>());
- }
- }
- inline bool issubclass(type derived, type base) {
- return py_issubclass(derived.index(), base.index());
- }
- template <typename T>
- inline bool isinstance(handle obj) {
- return type::isinstance<T>(obj);
- }
- template <>
- inline bool isinstance<handle>(handle) = delete;
- template <typename T, typename SFINAE = void>
- struct type_caster;
- template <typename T>
- object cast(T&& value,
- return_value_policy policy = return_value_policy::automatic_reference,
- handle parent = {}) {
- // decay_t can resolve c-array type, but remove_cv_ref_t can't.
- using underlying_type = std::decay_t<T>;
- if constexpr(std::is_convertible_v<underlying_type, handle> &&
- !is_pyobject_v<underlying_type>) {
- return object(std::forward<T>(value), object::realloc_t{});
- } else if constexpr(is_unique_pointer_v<underlying_type>) {
- using pointer = typename underlying_type::pointer;
- return type_caster<pointer>::cast(value.release(),
- return_value_policy::take_ownership,
- parent);
- } else {
- static_assert(!is_multiple_pointer_v<underlying_type>,
- "multiple pointer is not supported.");
- static_assert(!std::is_void_v<std::remove_pointer_t<underlying_type>>,
- "void* is not supported, consider using py::capsule.");
- // resolve for automatic policy.
- if(policy == return_value_policy::automatic) {
- policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
- : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
- : return_value_policy::move;
- } else if(policy == return_value_policy::automatic_reference) {
- policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
- : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
- : return_value_policy::move;
- }
- return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
- }
- }
- template <typename T>
- T cast(handle obj, bool convert = true) {
- using caster_t = type_caster<T>;
- constexpr auto is_dangling_v =
- (std::is_reference_v<T> || is_pointer_v<T>) && caster_t::is_temporary_v;
- static_assert(!is_dangling_v, "dangling reference or pointer is not allowed.");
- assert(obj.ptr() != nullptr);
- caster_t caster;
- if(caster.load(obj, convert)) {
- if constexpr(std::is_reference_v<T>) {
- return caster.value();
- } else {
- return std::move(caster.value());
- }
- } else {
- std::string msg = "cast python instance to c++ failed, obj type is: {";
- msg += type::of(obj).name();
- msg += "}, target type is: {";
- msg += type_name<T>();
- msg += "}.";
- throw cast_error(msg);
- }
- }
- template <typename Derived>
- template <typename T>
- T interface<Derived>::cast() const {
- return pkbind::cast<T>(handle(this->ptr()), true);
- }
- } // namespace pkbind
|