instance.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #pragma once
  2. #include "kernel.h"
  3. namespace pybind11 {
  4. struct type_info {
  5. const char* name;
  6. std::size_t size;
  7. std::size_t alignment;
  8. void (*destructor)(void*);
  9. void (*copy)(void*, const void*);
  10. void (*move)(void*, void*);
  11. const std::type_info* type;
  12. template <typename T>
  13. static type_info& of() {
  14. static_assert(!std::is_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
  15. "T must not be a reference type or const type.");
  16. static type_info info = {
  17. typeid(T).name(),
  18. sizeof(T),
  19. alignof(T),
  20. [](void* ptr) {
  21. ((T*)ptr)->~T();
  22. operator delete (ptr);
  23. },
  24. [](void* dst, const void* src) {
  25. new (dst) T(*(const T*)src);
  26. },
  27. [](void* dst, void* src) {
  28. new (dst) T(std::move(*(T*)src));
  29. },
  30. &typeid(T),
  31. };
  32. return info;
  33. }
  34. };
  35. // all registered C++ class will be ensured as instance type.
  36. class instance {
  37. public:
  38. // use to record the type information of C++ class.
  39. private:
  40. enum Flag {
  41. None = 0,
  42. Own = 1 << 0, // if the instance is owned by C++ side.
  43. Ref = 1 << 1, // need to mark the parent object.
  44. };
  45. Flag flag;
  46. void* data;
  47. const type_info* type;
  48. pkpy::PyVar parent;
  49. // pkpy::PyVar
  50. public:
  51. instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
  52. instance(const instance&) = delete;
  53. instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
  54. other.flag = Flag::None;
  55. other.data = nullptr;
  56. other.type = nullptr;
  57. other.parent = nullptr;
  58. }
  59. template <typename T>
  60. static pkpy::PyVar create(pkpy::Type type) {
  61. instance instance;
  62. instance.type = &type_info::of<T>();
  63. instance.data = operator new (sizeof(T));
  64. instance.flag = Flag::Own;
  65. return vm->new_object<pybind11::instance>(type, std::move(instance));
  66. }
  67. template <typename T>
  68. static pkpy::PyVar create(T&& value,
  69. pkpy::Type type,
  70. return_value_policy policy = return_value_policy::automatic_reference,
  71. pkpy::PyVar parent = nullptr) noexcept {
  72. using underlying_type = std::remove_cv_t<std::remove_reference_t<T>>;
  73. // resolve for automatic policy.
  74. if(policy == return_value_policy::automatic) {
  75. policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
  76. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  77. : return_value_policy::move;
  78. } else if(policy == return_value_policy::automatic_reference) {
  79. policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
  80. : std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
  81. : return_value_policy::move;
  82. }
  83. auto& _value = [&]() -> auto& {
  84. /**
  85. * note that, pybind11 will ignore the const qualifier.
  86. * in fact, try to modify a const value will result in undefined behavior.
  87. */
  88. if constexpr(std::is_pointer_v<underlying_type>) {
  89. return *reinterpret_cast<underlying_type*>(value);
  90. } else {
  91. return const_cast<underlying_type&>(value);
  92. }
  93. }();
  94. instance instance;
  95. instance.type = &type_info::of<underlying_type>();
  96. if(policy == return_value_policy::take_ownership) {
  97. instance.data = &_value;
  98. instance.flag = Flag::Own;
  99. } else if(policy == return_value_policy::copy) {
  100. instance.data = ::new auto(_value);
  101. instance.flag = Flag::Own;
  102. } else if(policy == return_value_policy::move) {
  103. instance.data = ::new auto(std::move(_value));
  104. instance.flag = Flag::Own;
  105. } else if(policy == return_value_policy::reference) {
  106. instance.data = &_value;
  107. instance.flag = Flag::None;
  108. } else if(policy == return_value_policy::reference_internal) {
  109. instance.data = &_value;
  110. instance.flag = Flag::Ref;
  111. instance.parent = parent;
  112. }
  113. return vm->new_object<pybind11::instance>(type, std::move(instance));
  114. }
  115. ~instance() {
  116. if(flag & Flag::Own) { type->destructor(data); }
  117. }
  118. void _gc_mark(pkpy::VM* vm) const noexcept {
  119. if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
  120. }
  121. template <typename T>
  122. T& cast() noexcept {
  123. return *static_cast<T*>(data);
  124. }
  125. };
  126. } // namespace pybind11