| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- #pragma once
- #include "types.h"
- #include "type_traits.h"
- namespace pybind11 {
- inline object eval(std::string_view code, const handle& global = none{}, handle local = none{}) {
- return vm->py_eval(code, global.ptr(), local.ptr());
- }
- inline void exec(std::string_view code, const handle& global = none{}, handle local = none{}) {
- vm->py_exec(code, global.ptr(), local.ptr());
- }
- /// globas() in pkpy is immutable, your changes will not be reflected in the Python interpreter
- inline dict globals() {
- auto& proxy = eval("globals()")._as<pkpy::MappingProxy>().attr();
- dict result;
- #if PK_VERSION_MAJOR == 2
- proxy.apply(
- [](pkpy::StrName key, pkpy::PyVar value, void* data) {
- auto& dict = static_cast<pybind11::dict*>(data)->_as<pkpy::Dict>();
- auto key_ = pybind11::str(key.sv()).ptr();
- dict.set(vm, key_, value);
- },
- &result);
- #else
- proxy.apply([&](pkpy::StrName key, pkpy::PyVar value) {
- result.setitem(str(key.sv()), value);
- });
- #endif
- return result;
- }
- // wrapper for builtin functions in Python
- inline bool hasattr(const handle& obj, const handle& name) {
- return vm->getattr(obj.ptr(), name._as<pkpy::Str>(), false) != nullptr;
- }
- inline bool hasattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name, false) != nullptr; }
- inline void delattr(const handle& obj, const handle& name) { vm->delattr(obj.ptr(), name._as<pkpy::Str>()); }
- inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); }
- inline object getattr(const handle& obj, const handle& name) { return vm->getattr(obj.ptr(), name._as<pkpy::Str>()); }
- inline object getattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name); }
- inline object getattr(const handle& obj, const handle& name, const handle& default_) {
- auto attr = vm->getattr(obj.ptr(), name._as<pkpy::Str>(), false);
- if(attr) { return attr; }
- return default_;
- }
- inline object getattr(const handle& obj, const char* name, const handle& default_) {
- auto attr = vm->getattr(obj.ptr(), name, false);
- if(attr) { return attr; }
- return default_;
- }
- inline void setattr(const handle& obj, const handle& name, const handle& value) {
- vm->setattr(obj.ptr(), name._as<pkpy::Str>(), value.ptr());
- }
- inline void setattr(const handle& obj, const char* name, const handle& value) {
- vm->setattr(obj.ptr(), name, value.ptr());
- }
- template <typename T>
- inline bool isinstance(const handle& obj) {
- return type_visitor::check<T>(obj);
- }
- template <>
- inline bool isinstance<handle>(const handle&) = delete;
- inline bool isinstance(const handle& obj, const handle& type) {
- return vm->isinstance(obj.ptr(), type._as<pkpy::Type>());
- }
- inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
- namespace impl {
- template <typename T, typename SFINAE = void>
- struct type_caster;
- }
- template <typename T>
- handle cast(T&& value, return_value_policy policy, 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>) {
- return std::forward<T>(value);
- } else if constexpr(is_unique_ptr_v<underlying_type>) {
- return impl::type_caster<typename underlying_type::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 impl::type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
- }
- }
- template <typename T>
- T cast(const handle& obj, bool convert) {
- assert(obj.ptr() != nullptr);
- impl::type_caster<T> caster = {};
- if(caster.load(obj, convert)) {
- return caster.value;
- } else {
- std::string msg = "cast python instance to c++ failed, ";
- msg += "obj type is: {";
- msg += type::of(obj).name();
- msg += "}, target type is: {";
- msg += type_name<T>();
- msg += "}.";
- vm->TypeError(msg);
- PK_UNREACHABLE();
- }
- }
- struct kwargs_proxy {
- handle value;
- };
- struct args_proxy {
- handle value;
- kwargs_proxy operator* () { return kwargs_proxy{value}; }
- };
- template <typename Derived>
- args_proxy interface<Derived>::operator* () const {
- return args_proxy{ptr()};
- }
- template <typename... Args>
- handle interpreter::vectorcall(const handle& callable, const handle& self, const Args&... args) {
- vm->s_data.push(callable.ptr());
- #if PK_VERSION_MAJOR == 2
- vm->s_data.push(self ? self.ptr() : PY_NULL);
- #else
- vm->s_data.push(self ? self.ptr() : pkpy::PY_NULL);
- #endif
- int argc = 0;
- int kwargsc = 0;
- auto push_arg = [&](const handle& value) {
- assert(value);
- vm->s_data.push(value.ptr());
- argc++;
- };
- auto push_named_arg = [&](std::string_view name, const handle& value) {
- assert(value);
- vm->s_data.push(int_(pkpy::StrName(name).index).ptr());
- vm->s_data.push(value.ptr());
- kwargsc++;
- };
- auto foreach_ = [&](const auto& arg) {
- using T = std::decay_t<decltype(arg)>;
- if constexpr(std::is_convertible_v<T, handle>) {
- push_arg(arg);
- } else if constexpr(std::is_same_v<T, args_proxy>) {
- pybind11::tuple args = arg.value.template cast<pybind11::tuple>();
- for(auto item: args) {
- push_arg(item);
- }
- } else if constexpr(std::is_same_v<T, pybind11::arg>) {
- push_named_arg(arg.name, arg.default_);
- } else if constexpr(std::is_same_v<T, kwargs_proxy>) {
- pybind11::dict kwargs = arg.value.template cast<pybind11::dict>();
- for(auto item: kwargs) {
- str name = item.first.template cast<str>();
- push_named_arg(name, item.second);
- }
- } else {
- static_assert(dependent_false<T>, "unsupported type");
- }
- };
- (foreach_(args), ...);
- return vm->vectorcall(argc, kwargsc);
- }
- template <typename Derived>
- template <return_value_policy policy, typename... Args>
- inline object interface<Derived>::operator() (Args&&... args) const {
- auto _cast = [&](auto&& arg) {
- using T = std::decay_t<decltype(arg)>;
- if constexpr(std::is_same_v<T, pybind11::arg> || std::is_same_v<T, kwargs_proxy> ||
- std::is_same_v<T, args_proxy> || std::is_convertible_v<T, handle>) {
- return arg;
- } else {
- return pybind11::cast(std::forward<decltype(arg)>(arg), policy);
- }
- };
- return interpreter::vectorcall(ptr(), handle(), _cast(std::forward<Args>(args))...);
- }
- template <typename... Args>
- void print(Args&&... args) {
- handle print = getattr(vm->builtins, "print");
- print(std::forward<Args>(args)...);
- }
- } // namespace pybind11
|