| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- #pragma once
- #include "kernel.h"
- namespace pybind11 {
- struct type_info {
- const char* name;
- std::size_t size;
- std::size_t alignment;
- void (*destructor)(void*);
- void (*copy)(void*, const void*);
- void (*move)(void*, void*);
- const std::type_info* type;
- template <typename T>
- static type_info& of() {
- static_assert(!std::is_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
- "T must not be a reference type or const type.");
- static type_info info = {
- typeid(T).name(),
- sizeof(T),
- alignof(T),
- [](void* ptr) {
- ((T*)ptr)->~T();
- operator delete (ptr);
- },
- [](void* dst, const void* src) {
- new (dst) T(*(const T*)src);
- },
- [](void* dst, void* src) {
- new (dst) T(std::move(*(T*)src));
- },
- &typeid(T),
- };
- return info;
- }
- };
- // all registered C++ class will be ensured as instance type.
- class instance {
- public:
- // use to record the type information of C++ class.
- private:
- enum Flag {
- None = 0,
- Own = 1 << 0, // if the instance is owned by C++ side.
- Ref = 1 << 1, // need to mark the parent object.
- };
- Flag flag;
- void* data;
- const type_info* type;
- pkpy::PyVar parent;
- // pkpy::PyVar
- public:
- instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
- instance(const instance&) = delete;
- instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
- other.flag = Flag::None;
- other.data = nullptr;
- other.type = nullptr;
- other.parent = nullptr;
- }
- template <typename T>
- static pkpy::PyVar create(pkpy::Type type) {
- instance instance;
- instance.type = &type_info::of<T>();
- instance.data = operator new (sizeof(T));
- instance.flag = Flag::Own;
- return vm->new_object<pybind11::instance>(type, std::move(instance));
- }
- template <typename T>
- static pkpy::PyVar create(T&& value,
- pkpy::Type type,
- return_value_policy policy = return_value_policy::automatic_reference,
- pkpy::PyVar parent = nullptr) noexcept {
- using underlying_type = std::remove_cv_t<std::remove_reference_t<T>>;
- // 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;
- }
- auto& _value = [&]() -> auto& {
- /**
- * note that, pybind11 will ignore the const qualifier.
- * in fact, try to modify a const value will result in undefined behavior.
- */
- if constexpr(std::is_pointer_v<underlying_type>) {
- return *reinterpret_cast<underlying_type*>(value);
- } else {
- return const_cast<underlying_type&>(value);
- }
- }();
- instance instance;
- instance.type = &type_info::of<underlying_type>();
- if(policy == return_value_policy::take_ownership) {
- instance.data = &_value;
- instance.flag = Flag::Own;
- } else if(policy == return_value_policy::copy) {
- instance.data = ::new auto(_value);
- instance.flag = Flag::Own;
- } else if(policy == return_value_policy::move) {
- instance.data = ::new auto(std::move(_value));
- instance.flag = Flag::Own;
- } else if(policy == return_value_policy::reference) {
- instance.data = &_value;
- instance.flag = Flag::None;
- } else if(policy == return_value_policy::reference_internal) {
- instance.data = &_value;
- instance.flag = Flag::Ref;
- instance.parent = parent;
- }
- return vm->new_object<pybind11::instance>(type, std::move(instance));
- }
- ~instance() {
- if(flag & Flag::Own) { type->destructor(data); }
- }
- void _gc_mark(pkpy::VM* vm) const noexcept {
- if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
- }
- template <typename T>
- T& cast() noexcept {
- return *static_cast<T*>(data);
- }
- };
- } // namespace pybind11
|