mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
220 lines
6.7 KiB
C++
220 lines
6.7 KiB
C++
#pragma once
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <pocketpy.h>
|
|
|
|
#include "type_traits.h"
|
|
|
|
namespace pybind11::impl {
|
|
struct capsule {
|
|
void* ptr;
|
|
void (*destructor)(void*);
|
|
|
|
template <typename T>
|
|
capsule(T&& value) :
|
|
ptr(new auto(std::forward<T>(value))), destructor([](void* ptr) {
|
|
delete static_cast<std::decay_t<T>*>(ptr);
|
|
}) {}
|
|
|
|
capsule(void* ptr, void (*destructor)(void*)) : ptr(ptr), destructor(destructor) {}
|
|
|
|
capsule(const capsule&) = delete;
|
|
|
|
capsule(capsule&& other) noexcept : ptr(other.ptr), destructor(other.destructor) {
|
|
other.ptr = nullptr;
|
|
other.destructor = nullptr;
|
|
}
|
|
|
|
~capsule() {
|
|
if(ptr != nullptr && destructor != nullptr) destructor(ptr);
|
|
}
|
|
};
|
|
} // namespace pybind11::impl
|
|
|
|
namespace pybind11 {
|
|
|
|
class handle;
|
|
class object;
|
|
class iterator;
|
|
class str;
|
|
struct arg;
|
|
struct args_proxy;
|
|
struct kwargs_proxy;
|
|
|
|
inline pkpy::VM* vm = nullptr;
|
|
|
|
class interpreter {
|
|
inline static std::vector<impl::capsule>* _capsules = nullptr;
|
|
inline static std::vector<void (*)()>* _init = nullptr;
|
|
|
|
public:
|
|
inline static void initialize(bool enable_os = true) {
|
|
if(vm == nullptr) {
|
|
vm = new pkpy::VM();
|
|
if(_init != nullptr) {
|
|
for(auto& fn: *_init)
|
|
fn();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline static void finalize() {
|
|
if(_capsules != nullptr) {
|
|
delete _capsules;
|
|
_capsules = nullptr;
|
|
}
|
|
|
|
if(vm != nullptr) {
|
|
delete vm;
|
|
vm = nullptr;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline static void* take_ownership(T&& value) {
|
|
if(_capsules == nullptr) _capsules = new std::vector<impl::capsule>();
|
|
_capsules->emplace_back(std::forward<T>(value));
|
|
return _capsules->back().ptr;
|
|
}
|
|
|
|
inline static void register_init(void (*init)()) {
|
|
if(_init == nullptr) _init = new std::vector<void (*)()>();
|
|
_init->push_back(init);
|
|
}
|
|
|
|
inline static pkpy::PyVar bind_func(pkpy::PyVar scope,
|
|
pkpy::StrName name,
|
|
int argc,
|
|
pkpy::NativeFuncC fn,
|
|
pkpy::any any = {},
|
|
pkpy::BindType type = pkpy::BindType::DEFAULT) {
|
|
#if PK_VERSION_MAJOR == 2
|
|
return vm->bind_func(scope.get(), name, argc, fn, any, type);
|
|
#else
|
|
return vm->bind_func(scope, name, argc, fn, std::move(any), type);
|
|
#endif
|
|
}
|
|
|
|
template <typename... Args>
|
|
inline static handle vectorcall(const handle& self, const handle& func, const Args&... args);
|
|
};
|
|
|
|
template <typename T>
|
|
constexpr inline bool need_host = !(std::is_trivially_copyable_v<T> && (sizeof(T) <= 8));
|
|
|
|
template <typename T>
|
|
decltype(auto) unpack(pkpy::ArgsView view) {
|
|
if constexpr(need_host<T>) {
|
|
void* data = pkpy::lambda_get_userdata<void*>(view.begin());
|
|
return *static_cast<T*>(data);
|
|
} else {
|
|
return pkpy::lambda_get_userdata<T>(view.begin());
|
|
}
|
|
}
|
|
|
|
template <typename policy>
|
|
class accessor;
|
|
|
|
namespace policy {
|
|
struct attr;
|
|
struct item;
|
|
struct tuple;
|
|
struct list;
|
|
struct dict;
|
|
} // namespace policy
|
|
|
|
using attr_accessor = accessor<policy::attr>;
|
|
using item_accessor = accessor<policy::item>;
|
|
using tuple_accessor = accessor<policy::tuple>;
|
|
using list_accessor = accessor<policy::list>;
|
|
using dict_accessor = accessor<policy::dict>;
|
|
|
|
template <typename T>
|
|
T cast(const handle& obj, bool convert = false);
|
|
|
|
enum class return_value_policy : uint8_t {
|
|
/**
|
|
* This is the default return value policy, which falls back to the policy
|
|
* return_value_policy::take_ownership when the return value is a pointer.
|
|
* Otherwise, it uses return_value::move or return_value::copy for rvalue
|
|
* and lvalue references, respectively. See below for a description of what
|
|
* all of these different policies do.
|
|
*/
|
|
automatic = 0,
|
|
|
|
/**
|
|
* As above, but use policy return_value_policy::reference when the return
|
|
* value is a pointer. This is the default conversion policy for function
|
|
* arguments when calling Python functions manually from C++ code (i.e. via
|
|
* handle::operator()). You probably won't need to use this.
|
|
*/
|
|
automatic_reference,
|
|
|
|
/**
|
|
* Reference an existing object (i.e. do not create a new copy) and take
|
|
* ownership. Python will call the destructor and delete operator when the
|
|
* object's reference count reaches zero. Undefined behavior ensues when
|
|
* the C++ side does the same..
|
|
*/
|
|
take_ownership,
|
|
|
|
/**
|
|
* Create a new copy of the returned object, which will be owned by
|
|
* Python. This policy is comparably safe because the lifetimes of the two
|
|
* instances are decoupled.
|
|
*/
|
|
copy,
|
|
|
|
/**
|
|
* Use std::move to move the return value contents into a new instance
|
|
* that will be owned by Python. This policy is comparably safe because the
|
|
* lifetimes of the two instances (move source and destination) are
|
|
* decoupled.
|
|
*/
|
|
move,
|
|
|
|
/**
|
|
* Reference an existing object, but do not take ownership. The C++ side
|
|
* is responsible for managing the object's lifetime and deallocating it
|
|
* when it is no longer used. Warning: undefined behavior will ensue when
|
|
* the C++ side deletes an object that is still referenced and used by
|
|
* Python.
|
|
*/
|
|
reference,
|
|
|
|
/**
|
|
* This policy only applies to methods and properties. It references the
|
|
* object without taking ownership similar to the above
|
|
* return_value_policy::reference policy. In contrast to that policy, the
|
|
* function or property's implicit this argument (called the parent) is
|
|
* considered to be the the owner of the return value (the child).
|
|
* pybind11 then couples the lifetime of the parent to the child via a
|
|
* reference relationship that ensures that the parent cannot be garbage
|
|
* collected while Python is still using the child. More advanced
|
|
* variations of this scheme are also possible using combinations of
|
|
* return_value_policy::reference and the keep_alive call policy
|
|
*/
|
|
reference_internal
|
|
};
|
|
|
|
struct empty {};
|
|
|
|
template <typename... Args>
|
|
void print(Args&&... args);
|
|
|
|
class object;
|
|
|
|
template <typename T>
|
|
constexpr inline bool is_pyobject_v = std::is_base_of_v<object, T>;
|
|
|
|
#if PK_VERSION_MAJOR == 2
|
|
using error_already_set = pkpy::TopLevelException;
|
|
#else
|
|
using error_already_set = pkpy::Exception;
|
|
#endif
|
|
|
|
inline void setattr(const handle& obj, const handle& name, const handle& value);
|
|
inline void setattr(const handle& obj, const char* name, const handle& value);
|
|
|
|
} // namespace pybind11
|